@mastra/factory 0.26.0-alpha.1 → 0.26.0-alpha.3
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/README.md +74 -7
- package/dist/boards/define-board.d.ts +19 -0
- package/dist/boards/define-board.d.ts.map +1 -1
- package/dist/boards/define-board.js +41 -9
- package/dist/boards/define-board.js.map +1 -1
- package/dist/boards/project-boards.d.ts +78 -0
- package/dist/boards/project-boards.d.ts.map +1 -0
- package/dist/boards/project-boards.js +194 -0
- package/dist/boards/project-boards.js.map +1 -0
- package/dist/boards/review.js +2 -2
- package/dist/boards/review.js.map +1 -1
- package/dist/boards/stored-board.d.ts +101 -0
- package/dist/boards/stored-board.d.ts.map +1 -0
- package/dist/boards/stored-board.js +139 -0
- package/dist/boards/stored-board.js.map +1 -0
- package/dist/boards/work.d.ts.map +1 -1
- package/dist/boards/work.js +6 -3
- package/dist/boards/work.js.map +1 -1
- package/dist/capabilities/intake.d.ts +6 -0
- package/dist/capabilities/intake.d.ts.map +1 -1
- package/dist/environment/build.d.ts +1 -1
- package/dist/environment/build.d.ts.map +1 -1
- package/dist/environment/build.js +2 -0
- package/dist/environment/build.js.map +1 -1
- package/dist/factory.d.ts +15 -2
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +51 -12
- package/dist/factory.js.map +1 -1
- package/dist/integrations/github/integration.d.ts +5 -4
- package/dist/integrations/github/integration.d.ts.map +1 -1
- package/dist/integrations/github/integration.js +10 -8
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/sandbox.d.ts +2 -2
- package/dist/integrations/github/sandbox.d.ts.map +1 -1
- package/dist/integrations/github/sandbox.js +6 -1
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/jira/binding-scope.d.ts +30 -0
- package/dist/integrations/jira/binding-scope.d.ts.map +1 -0
- package/dist/integrations/jira/binding-scope.js +50 -0
- package/dist/integrations/jira/binding-scope.js.map +1 -0
- package/dist/integrations/jira/claim.d.ts +12 -0
- package/dist/integrations/jira/claim.d.ts.map +1 -1
- package/dist/integrations/jira/claim.js +24 -1
- package/dist/integrations/jira/claim.js.map +1 -1
- package/dist/integrations/jira/intake-jql.d.ts +32 -0
- package/dist/integrations/jira/intake-jql.d.ts.map +1 -0
- package/dist/integrations/jira/intake-jql.js +57 -0
- package/dist/integrations/jira/intake-jql.js.map +1 -0
- package/dist/integrations/jira/integration.d.ts +4 -3
- package/dist/integrations/jira/integration.d.ts.map +1 -1
- package/dist/integrations/jira/integration.js +14 -21
- package/dist/integrations/jira/integration.js.map +1 -1
- package/dist/integrations/jira/routes.d.ts +3 -0
- package/dist/integrations/jira/routes.d.ts.map +1 -1
- package/dist/integrations/jira/routes.js +16 -29
- package/dist/integrations/jira/routes.js.map +1 -1
- package/dist/integrations/jira/rules.d.ts.map +1 -1
- package/dist/integrations/jira/rules.js +8 -13
- package/dist/integrations/jira/rules.js.map +1 -1
- package/dist/integrations/platform/github/integration.d.ts +5 -0
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +7 -0
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/integrations/platform/jira/integration.d.ts +7 -1
- package/dist/integrations/platform/jira/integration.d.ts.map +1 -1
- package/dist/integrations/platform/jira/integration.js +26 -24
- package/dist/integrations/platform/jira/integration.js.map +1 -1
- package/dist/integrations/platform/jira/routes.d.ts +3 -0
- package/dist/integrations/platform/jira/routes.d.ts.map +1 -1
- package/dist/integrations/platform/jira/routes.js +17 -28
- package/dist/integrations/platform/jira/routes.js.map +1 -1
- package/dist/routes/attention-providers.d.ts +2 -1
- package/dist/routes/attention-providers.d.ts.map +1 -1
- package/dist/routes/attention-providers.js +3 -2
- package/dist/routes/attention-providers.js.map +1 -1
- package/dist/routes/attention.d.ts +2 -1
- package/dist/routes/attention.d.ts.map +1 -1
- package/dist/routes/attention.js.map +1 -1
- package/dist/routes/boards.d.ts +30 -0
- package/dist/routes/boards.d.ts.map +1 -0
- package/dist/routes/boards.js +272 -0
- package/dist/routes/boards.js.map +1 -0
- package/dist/routes/contracts.d.ts +249 -0
- package/dist/routes/contracts.d.ts.map +1 -1
- package/dist/routes/contracts.js +107 -35
- package/dist/routes/contracts.js.map +1 -1
- package/dist/routes/intake.d.ts +15 -10
- package/dist/routes/intake.d.ts.map +1 -1
- package/dist/routes/intake.js +109 -22
- package/dist/routes/intake.js.map +1 -1
- package/dist/routes/projects.d.ts +3 -0
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +10 -1
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/surface.d.ts +10 -3
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +13 -1
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/tenant-credentials.d.ts +9 -0
- package/dist/routes/tenant-credentials.d.ts.map +1 -1
- package/dist/routes/tenant-credentials.js +24 -2
- package/dist/routes/tenant-credentials.js.map +1 -1
- package/dist/routes/work-items.d.ts +3 -1
- package/dist/routes/work-items.d.ts.map +1 -1
- package/dist/routes/work-items.js +64 -42
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/dispatch-errors.d.ts.map +1 -1
- package/dist/rules/dispatch-errors.js +4 -0
- package/dist/rules/dispatch-errors.js.map +1 -1
- package/dist/rules/dispatcher.d.ts +7 -1
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +70 -34
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/processor.d.ts +3 -1
- package/dist/rules/processor.d.ts.map +1 -1
- package/dist/rules/processor.js +11 -6
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/tools.d.ts +2 -1
- package/dist/rules/tools.d.ts.map +1 -1
- package/dist/rules/tools.js +2 -1
- package/dist/rules/tools.js.map +1 -1
- package/dist/rules/transition-service.d.ts +3 -1
- package/dist/rules/transition-service.d.ts.map +1 -1
- package/dist/rules/transition-service.js +12 -12
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/sandbox/local-factory-sandbox.d.ts +4 -1
- package/dist/sandbox/local-factory-sandbox.d.ts.map +1 -1
- package/dist/sandbox/local-factory-sandbox.js +1 -1
- package/dist/sandbox/local-factory-sandbox.js.map +1 -1
- package/dist/storage/domains/audit/actions.d.ts +1 -0
- package/dist/storage/domains/audit/actions.d.ts.map +1 -1
- package/dist/storage/domains/audit/actions.js +6 -1
- package/dist/storage/domains/audit/actions.js.map +1 -1
- package/dist/storage/domains/boards/base.d.ts +110 -0
- package/dist/storage/domains/boards/base.d.ts.map +1 -0
- package/dist/storage/domains/boards/base.js +292 -0
- package/dist/storage/domains/boards/base.js.map +1 -0
- package/dist/storage/domains/boards/schemas.d.ts +11 -0
- package/dist/storage/domains/boards/schemas.d.ts.map +1 -0
- package/dist/storage/domains/boards/schemas.js +106 -0
- package/dist/storage/domains/boards/schemas.js.map +1 -0
- package/dist/storage/domains/credentials/base.d.ts +4 -1
- package/dist/storage/domains/credentials/base.d.ts.map +1 -1
- package/dist/storage/domains/credentials/base.js +5 -2
- package/dist/storage/domains/credentials/base.js.map +1 -1
- package/dist/storage/domains/intake/base.d.ts +86 -5
- package/dist/storage/domains/intake/base.d.ts.map +1 -1
- package/dist/storage/domains/intake/base.js +298 -59
- package/dist/storage/domains/intake/base.js.map +1 -1
- package/dist/storage/domains/projects/base.d.ts +2 -1
- package/dist/storage/domains/projects/base.d.ts.map +1 -1
- package/dist/storage/domains/projects/base.js +15 -10
- package/dist/storage/domains/projects/base.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +16 -2
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +40 -11
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/tools/read-tools.d.ts +3 -1
- package/dist/tools/read-tools.d.ts.map +1 -1
- package/dist/tools/read-tools.js +3 -2
- package/dist/tools/read-tools.js.map +1 -1
- package/dist/tools/session-tools.d.ts +3 -1
- package/dist/tools/session-tools.d.ts.map +1 -1
- package/dist/tools/session-tools.js +2 -1
- package/dist/tools/session-tools.js.map +1 -1
- package/dist/tools/sessions-state-processor.d.ts +3 -1
- package/dist/tools/sessions-state-processor.d.ts.map +1 -1
- package/dist/tools/sessions-state-processor.js +2 -1
- package/dist/tools/sessions-state-processor.js.map +1 -1
- package/dist/tools/work-item-tools.d.ts +3 -1
- package/dist/tools/work-item-tools.d.ts.map +1 -1
- package/dist/tools/work-item-tools.js +3 -2
- package/dist/tools/work-item-tools.js.map +1 -1
- package/dist/workspace.d.ts +2 -0
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +14 -5
- package/dist/workspace.js.map +1 -1
- package/factory-skills/factory-plan/SKILL.md +1 -1
- package/factory-skills/factory-triage/SKILL.md +18 -7
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -55,9 +55,76 @@ MASTRA_TELEMETRY_DISABLED=true
|
|
|
55
55
|
|
|
56
56
|
`1`, `true`, and `yes` are accepted, ignoring case and surrounding whitespace. Older servers without the explicit capability do not receive browser telemetry requests. Custom auth providers are outside this initial measurement scope until they have a stable identity namespace. No names, emails, tokens, prompts, input values, raw URLs, session replay, or anonymous browser identity are collected by this event. Account IDs are identifiable account data, not anonymous data.
|
|
57
57
|
|
|
58
|
+
### Stored boards
|
|
59
|
+
|
|
60
|
+
Each project has two kinds of boards:
|
|
61
|
+
|
|
62
|
+
- **Code boards**: the built-in Work and Review boards and the boards you pass to `new MastraFactory({ boards })`. Factory serves them to every project exactly as your code defines them. They are never written to the database and are read-only in the boards API.
|
|
63
|
+
- **Stored boards**: boards an admin created for one project through the boards API. They live in that project's database.
|
|
64
|
+
|
|
65
|
+
A project's boards are its code boards followed by its stored boards. The catalog, card creation through the API and Factory tools, transitions, the dispatcher, phase runs and the attention views all read that list. When a stored board has the same key as a code board, the code board wins: the stored board is hidden and the catalog reports `Stored board "<key>" is hidden by the code board with the same key.` Existing apps need no change, and Factory writes nothing to the database at startup.
|
|
66
|
+
|
|
67
|
+
**Data model.** A stored board has a `key` (the ID cards reference as `board`), `name`, optional `description`, and ordered phases. A phase has a `key` (the stage ID), `name`, optional `description`, `kind`, and for working phases `runner` (`{ skill?, context?, instructions? }`), `autoStart`, `autoStartWhen` and `exitTool`, plus `nextPhases`. The first phase is the initial phase and must be `resting`. Saved boards pass the same checks `defineBoard()` applies, with the same messages. A stored board has no code behaviors: no handlers, transition policy, `sourceClosed`, or tool and event rules. Its working phases start their `runner` on entry.
|
|
68
|
+
|
|
69
|
+
`nextPhases` on a stored board: leaving it out (or `null`) on a resting or working phase allows moves to every other phase, `[]` allows none, and a terminal phase allows none unless it lists some.
|
|
70
|
+
|
|
71
|
+
**Code boards are read-only.** The catalog and `GET …/boards/:boardKey` report each board's `source` (`builtin`, `app` or `stored`) and `editable` (`false` for code boards). Creating a board with a code board's key, or editing or deleting a code board, is refused with `409 code_board`. Change a code board in code; every project picks up the change when Factory restarts.
|
|
72
|
+
|
|
73
|
+
**Editing rules for stored boards.**
|
|
74
|
+
|
|
75
|
+
- Board and phase keys never change. Renaming changes `name`. Any phase may become the first phase, as long as it is `resting`.
|
|
76
|
+
- Removing a phase, or changing its `kind`, while cards sit in it is refused with `409 phase_in_use` and the count per phase. Deleting a board that has cards is refused with `409 board_in_use`. Factory never moves cards for you. A card created between the check and the write can still land on a removed phase; it then shows as an unsupported item until it is moved.
|
|
77
|
+
- A runner skill that does not exist is refused (`422 unknown_skill`). A review skill outside the `review` context is saved with a warning in `problems`. A skill that disappears later never stops a board from loading; it shows in the catalog's `problems`.
|
|
78
|
+
|
|
79
|
+
**Replicas.** Each board write replaces the project's board version. The replica that wrote it sees the change at once; other replicas notice within a second, the next time they touch that project.
|
|
80
|
+
|
|
81
|
+
**Integrations.** Integration event rules, reconcilers and the code that files new cards from integrations read only the code boards. Intake bindings and label routes can target only code boards. Every card move goes through the transition service, which checks it against the project's boards.
|
|
82
|
+
|
|
83
|
+
**Routes.** All need project membership; changes need an organization admin when auth is enabled, and are recorded in the audit log as `factory.board.created`, `updated` and `deleted`.
|
|
84
|
+
|
|
85
|
+
| Method | Path | Body | Result |
|
|
86
|
+
| -------- | --------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
87
|
+
| `GET` | `/web/factory/projects/:id/boards` | — | The catalog, with each board's `source`, `editable` and `problems`. |
|
|
88
|
+
| `GET` | `/web/factory/projects/:id/boards/:boardKey` | — | The definition, `revision` (`null` for code boards), `source`, `editable` and `problems`. |
|
|
89
|
+
| `POST` | `/web/factory/projects/:id/boards` | The board, with `key`. | `201` and the board. `409 code_board` for a code board's key, `409 board_exists` for a stored board's. |
|
|
90
|
+
| `PATCH` | `/web/factory/projects/:id/boards/:boardKey` | The whole board without `key`, plus `expectedRevision`. | The board. Replaces every field. `409 code_board` for a code board. |
|
|
91
|
+
| `DELETE` | `/web/factory/projects/:id/boards/:boardKey?expectedRevision=n` | — | `204`. `409 code_board` for a code board. |
|
|
92
|
+
|
|
93
|
+
A stale `expectedRevision` is refused with `409 revision_mismatch`; reload the board and try again.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Create a board.
|
|
97
|
+
curl -X POST "$FACTORY_URL/web/factory/projects/$PROJECT/boards" -H 'content-type: application/json' -d '{
|
|
98
|
+
"key": "bugs",
|
|
99
|
+
"name": "Bugs",
|
|
100
|
+
"phases": [
|
|
101
|
+
{ "key": "reported", "name": "Reported", "kind": "resting" },
|
|
102
|
+
{ "key": "fixing", "name": "Fixing", "kind": "working", "runner": { "context": "work" } },
|
|
103
|
+
{ "key": "fixed", "name": "Fixed", "kind": "terminal" }
|
|
104
|
+
]
|
|
105
|
+
}'
|
|
106
|
+
|
|
107
|
+
# Rename its Fixing phase: read the board, change it, send it back with its revision.
|
|
108
|
+
curl "$FACTORY_URL/web/factory/projects/$PROJECT/boards/bugs" > bugs.json
|
|
109
|
+
jq '.board | { name, description, phases: (.phases | map(if .key == "fixing" then .name = "Patching" else . end)), expectedRevision: .revision }' bugs.json \
|
|
110
|
+
| curl -X PATCH "$FACTORY_URL/web/factory/projects/$PROJECT/boards/bugs" -H 'content-type: application/json' -d @-
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Migrating from `defineBoard()`
|
|
114
|
+
|
|
115
|
+
`defineBoard()`, and the `boards` and `includeDefaultBoards` options of `MastraFactory`, are deprecated. Nothing breaks: the boards you pass keep working as read-only code boards, they are not stored, and Factory logs once per process:
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
[Mastra Factory] MastraFactory({ boards }) and defineBoard() are deprecated: boards now live in the database, and these definitions are served read-only next to the boards each project stores. Manage boards through the boards API; see the README "Stored boards" section.
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Using only the built-in boards logs nothing. A board that cards reach only through the API, the Factory UI or Factory tools, and that needs no handlers, policies or rules, can move off code: create it in each project with `POST /web/factory/projects/:id/boards` under a new key, move its cards, then stop passing the code board. Keep passing a board while integrations file cards onto it, intake bindings or label routes target it, or it needs code behaviors.
|
|
122
|
+
|
|
123
|
+
Removing `defineBoard()` needs, among other things, a one-time copy of the code boards into each project's database, so built-in and app boards become editable stored boards. That work is tracked in [mastra-ai/mastra#28920](https://github.com/mastra-ai/mastra/issues/28920).
|
|
124
|
+
|
|
58
125
|
### Board lifecycle rules
|
|
59
126
|
|
|
60
|
-
|
|
127
|
+
Code boards own phase entry and exit handlers; stored boards have none (see [Stored boards](#stored-boards)). Work and Review are installed automatically with Mastra's preferred defaults; no rule configuration is needed. Custom boards declare source-specific `onEnter` and `onExit` handlers through `defineBoard()`, which is deprecated but still works:
|
|
61
128
|
|
|
62
129
|
```typescript
|
|
63
130
|
import { MastraFactory } from '@mastra/factory';
|
|
@@ -277,7 +344,7 @@ A policy cannot bypass topology, ingress authorization, board ownership, externa
|
|
|
277
344
|
|
|
278
345
|
### Board phase semantics
|
|
279
346
|
|
|
280
|
-
Every phase declares what it _is_ with a required `kind`; `defineBoard()`
|
|
347
|
+
Every phase declares what it _is_ with a required `kind`; `defineBoard()` and the boards API reject a phase without one.
|
|
281
348
|
|
|
282
349
|
- `resting` — the card is parked. A human move out of a resting phase arms autonomy; a move back into one disarms it. `initialPhase` must be resting: a card cannot arrive already seated or already finished.
|
|
283
350
|
- `working` — an agent carries the card. `runner.context` (same identifier rules as decision roles, default `work`) names the session context a human kickoff opens and the lane a rule-started run leaves rest for. Two working phases may share a context, and then a session; `phaseForRole` returns the first in declaration order.
|
|
@@ -300,7 +367,7 @@ Work declares `intake` resting; `triage`, `planning`, `execute`, and `review` wo
|
|
|
300
367
|
|
|
301
368
|
Planning and Building on Work share the `work` session, so the builder keeps the planner's reasoning, branch and sandbox. Self-review still runs in its own `review` session. When the planner moves the card to Building, the build prompt is queued onto its own run, and the planner's run binding ends at that point: Factory tools it calls later in the same turn are rejected. When the builder moves a card back from Building to Planning, no new planning run starts; the builder keeps working in its run. When a person moves it back, Planning starts again, in the same `work` session. The old `plan` role still names Planning: a run requested or queued for `plan` starts Planning in a `plan` session, and the build then continues in that session. Cards planned before this change do the same.
|
|
302
369
|
|
|
303
|
-
Consent, the external-author guard, kickoff seating, run-start lanes, terminal cleanup, and the closed-PR and issue sweeps all read the
|
|
370
|
+
Consent, the external-author guard, kickoff seating, run-start lanes, terminal cleanup, and the closed-PR and issue sweeps all read the project's board; nothing name-matches phases. A board that reuses Work's phase names gets exactly what it declared. Persisted `board` is authoritative; rows without one are read as Review for pull requests and Work otherwise.
|
|
304
371
|
|
|
305
372
|
Unknown semantics fail closed. When the board is not installed or the phase is not declared: external-event transitions ask for consent, no sweep or cleanup treats the card as finished, and a rule-started run from rest with no lane for its role is rejected.
|
|
306
373
|
|
|
@@ -356,7 +423,7 @@ const releaseBoard = defineBoard({
|
|
|
356
423
|
});
|
|
357
424
|
```
|
|
358
425
|
|
|
359
|
-
**Migration:** `defineBoard()` still accepts the old field names and maps them to the new ones straight away: `title` → `name`, `role` → `runner.context`, `next` → `nextPhases`. It logs one warning per board that still uses them. Setting both `title` and `name`, or `role` and `runner.context`, to different values is rejected. `outcomes` is not deprecated: its targets are added to `nextPhases` and outcome names keep working. The board `defineBoard()` returns
|
|
426
|
+
**Migration:** `defineBoard()` still accepts the old field names and maps them to the new ones straight away: `title` → `name`, `role` → `runner.context`, `next` → `nextPhases`. It logs one warning per board that still uses them. Setting both `title` and `name`, or `role` and `runner.context`, to different values is rejected. `outcomes` is not deprecated: its targets are added to `nextPhases` and outcome names keep working. The board `defineBoard()` returns still has the old names as read-only copies — `board.title` and `phase.title` equal `name`, a working phase's `role` equals `runner.context`, and `phase.next` is set when the phase declared `next` — so code that reads them, or passes a defined board's phases to `defineBoard()` again, keeps working. They are deprecated; read `name`, `runner.context` and `nextPhases` instead. The board catalog (`GET /web/factory/projects/:id/boards`) still sends `title` and `role` beside the new fields for older clients. Card session keys do not change: a phase's context is its old role.
|
|
360
427
|
|
|
361
428
|
### Skills for custom boards
|
|
362
429
|
|
|
@@ -419,7 +486,7 @@ Settings › Skills shows the skill each custom phase runs, marks a phase whose
|
|
|
419
486
|
|
|
420
487
|
### Execute a custom board
|
|
421
488
|
|
|
422
|
-
|
|
489
|
+
Custom boards can create linked items, start working roles, transition through bound tools, and react to completed tool results. Board and phase identifiers contain 1–128 letters, digits, underscores, or hyphens and start with a letter or digit. Identifiers are case-sensitive and cannot contain surrounding whitespace.
|
|
423
490
|
|
|
424
491
|
This configuration runs a release rehearsal through `backlog → preparing → build → done`. Add it to an existing Factory host with configured storage, a GitHub integration, a connected project repository, a sandbox, and organization-scoped model credentials. Enable automatic runs for the project. The repository must contain a `release:check` package script; it should validate the release without publishing it.
|
|
425
492
|
|
|
@@ -515,7 +582,7 @@ Custom phase signals and persisted tool-result ingestion use the item's installe
|
|
|
515
582
|
|
|
516
583
|
### Custom boards in the Factory UI
|
|
517
584
|
|
|
518
|
-
`GET /web/factory/projects/:id/boards` returns the
|
|
585
|
+
`GET /web/factory/projects/:id/boards` returns the project's boards (its code boards, then its stored boards) for an authorized user: each board's `id`, `title`, `initialPhase`, declaration-ordered `phases` (with `kind`, and for working phases `role` and the `skill` the runner starts), and transition topology. Handlers, policies, and prompts are never serialized. The Factory UI reads this catalog instead of assuming Work and Review:
|
|
519
586
|
|
|
520
587
|
- Installed boards appear in the sidebar — built-ins first, then custom boards in registry order. Work and Review keep `/factories/:id/work` and `/factories/:id/review`; custom boards open at `/factories/:id/boards/:boardId`. An unknown board ID or a failed catalog request shows an explicit unavailable state rather than falling back to Work.
|
|
521
588
|
- Columns, phase labels, and working/terminal presentation come from the phase definitions. Card creation sends the selected `board`, so the server picks the initial phase. Card menus offer only moves the topology declares; the server still enforces policy, authorization, and revisions.
|
|
@@ -528,7 +595,7 @@ Custom phase signals and persisted tool-result ingestion use the item's installe
|
|
|
528
595
|
Intake bindings are explicit. A Linear project, Jira project, or GitHub repository is only offered as a candidate feed once it is bound to a board; nothing is materialized just by opening a board. Review only accepts pull requests and is not offered for issue routing.
|
|
529
596
|
|
|
530
597
|
- **Linear:** each project binding selects one installed board. Changing the board moves that source's existing cards to the new board's initial phase, skipping terminal cards and cards with an active session.
|
|
531
|
-
- **Jira:** each connected-site project binding selects one installed board. The create-Factory flow can select a Jira project and initially binds it to Work. The browser checks routed projects for new issues every 30 seconds and on window focus; issues observed for a routed project materialize automatically as work items on the bound board (mirroring Linear), and closed issues transition their linked card to done or canceled. Both `JiraIntegration` and `PlatformJiraIntegration` reconcile imported cards every five minutes by default so status and metadata continue to refresh without an open browser, and both accept a `rules` option to replace or disable the `issueObserved` / `issueClosed` defaults. Agents on Jira-sourced runs get `jira_get_issue` and `jira_create_comment`. Set `MASTRACODE_JIRA_RECONCILE_ENABLED=false` to disable reconciliation or `MASTRACODE_JIRA_RECONCILE_INTERVAL_MS` to a positive millisecond interval to change its cadence.
|
|
598
|
+
- **Jira:** each connected-site project binding selects one installed board. One Jira project can feed several Factory projects: each binding takes either all issues or only issues carrying its labels (Settings › Intake › Jira routing, or `labels` on `PUT /web/intake/bindings`). Each label belongs to one binding per Jira project, and only one binding per project can take all issues. Label bindings win over the all-issues binding; an issue carrying labels of two label bindings goes to the binding created first. The split happens in the JQL each Factory sends, so every issue is filed in exactly one Factory. Labels only decide placement when an issue is first filed: relabelling an issue, or editing a binding's labels, does not move existing cards. Remove one Factory's binding with `DELETE /web/intake/bindings?integrationId=jira&sourceId=…&factoryProjectId=…`. The create-Factory flow can select a Jira project and initially binds it to Work. The browser checks routed projects for new issues every 30 seconds and on window focus; issues observed for a routed project materialize automatically as work items on the bound board (mirroring Linear), and closed issues transition their linked card to done or canceled. Both `JiraIntegration` and `PlatformJiraIntegration` reconcile imported cards every five minutes by default so status and metadata continue to refresh without an open browser, and both accept a `rules` option to replace or disable the `issueObserved` / `issueClosed` defaults. Agents on Jira-sourced runs get `jira_get_issue` and `jira_create_comment`. Set `MASTRACODE_JIRA_RECONCILE_ENABLED=false` to disable reconciliation or `MASTRACODE_JIRA_RECONCILE_INTERVAL_MS` to a positive millisecond interval to change its cadence.
|
|
532
599
|
- **GitHub:** Settings › Intake › GitHub routing maps a label to a board per Factory project (`GET`/`PUT /web/intake/label-routes`). Labels match case-insensitively; unrouted issues go to Work. Saving a route relocates matching cards the same way, and `issues.labeled` / `issues.unlabeled` webhooks move a card between its routed board and Work while refreshing its label metadata. Routes apply to every repository linked to the project; label input is free text (no repository label autocomplete yet).
|
|
533
600
|
|
|
534
601
|
### GitHub event rules
|
|
@@ -112,9 +112,13 @@ export type BoardPhaseDefinition<PhaseId extends string> = (BoardPhaseBase<Phase
|
|
|
112
112
|
});
|
|
113
113
|
type ResolvedPhaseBase<PhaseId extends string> = {
|
|
114
114
|
readonly name: string;
|
|
115
|
+
/** @deprecated Use `name`; kept equal to it for code written against older Factory versions. */
|
|
116
|
+
readonly title: string;
|
|
115
117
|
readonly description?: string;
|
|
116
118
|
/** Every phase a card may move to from here, including outcome targets. */
|
|
117
119
|
readonly nextPhases: readonly PhaseId[];
|
|
120
|
+
/** @deprecated Use `nextPhases`; set when the phase declared `next`. */
|
|
121
|
+
readonly next?: PhaseId;
|
|
118
122
|
readonly outcomes?: Readonly<Record<string, PhaseId>>;
|
|
119
123
|
readonly onEnter?: ReadonlyBoardPhaseHandlers;
|
|
120
124
|
readonly onExit?: ReadonlyBoardPhaseHandlers;
|
|
@@ -131,6 +135,8 @@ export type BoardPhase<PhaseId extends string> = (ResolvedPhaseBase<PhaseId> & {
|
|
|
131
135
|
agentId: string;
|
|
132
136
|
context: string;
|
|
133
137
|
}>;
|
|
138
|
+
/** @deprecated Use `runner.context`; kept equal to it. */
|
|
139
|
+
readonly role: string;
|
|
134
140
|
readonly autoStart?: boolean;
|
|
135
141
|
readonly autoStartWhen?: RuleGroup;
|
|
136
142
|
readonly exitTool?: Readonly<{
|
|
@@ -156,6 +162,8 @@ export type BoardSourceClosed<PhaseId extends string> = Readonly<{
|
|
|
156
162
|
export interface BoardDefinition<BoardId extends string, PhaseId extends string> {
|
|
157
163
|
readonly id: BoardId;
|
|
158
164
|
readonly name: string;
|
|
165
|
+
/** @deprecated Use `name`; kept equal to it for code written against older Factory versions. */
|
|
166
|
+
readonly title: string;
|
|
159
167
|
readonly description?: string;
|
|
160
168
|
readonly initialPhase: PhaseId;
|
|
161
169
|
readonly phases: Readonly<Record<PhaseId, BoardPhase<PhaseId>>>;
|
|
@@ -202,6 +210,17 @@ type BoardConfig<BoardId extends string, Phases extends Record<string, BoardPhas
|
|
|
202
210
|
export declare class BoardDefinitionError extends Error {
|
|
203
211
|
name: string;
|
|
204
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Declares a board in code.
|
|
215
|
+
*
|
|
216
|
+
* @deprecated Boards are stored per project; manage them with `/web/factory/projects/:id/boards`
|
|
217
|
+
* (README § Stored boards). Code boards are read-only and served alongside each project's stored
|
|
218
|
+
* boards.
|
|
219
|
+
*/
|
|
205
220
|
export declare function defineBoard<const BoardId extends string, const Phases extends Record<string, BoardPhaseDefinition<keyof Phases & string>>>(config: BoardConfig<BoardId, Phases>): BoardDefinition<BoardId, keyof Phases & string>;
|
|
221
|
+
/** Whether an app declared the board with the deprecated `defineBoard()`. */
|
|
222
|
+
export declare function isDefinedBoard(board: object): boolean;
|
|
223
|
+
/** Validates and resolves a board declaration. Factory's own boards use this directly. */
|
|
224
|
+
export declare function compileBoardDefinition<const BoardId extends string, const Phases extends Record<string, BoardPhaseDefinition<keyof Phases & string>>>(config: BoardConfig<BoardId, Phases>): BoardDefinition<BoardId, keyof Phases & string>;
|
|
206
225
|
export {};
|
|
207
226
|
//# sourceMappingURL=define-board.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-board.d.ts","sourceRoot":"","sources":["../../src/boards/define-board.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"define-board.d.ts","sourceRoot":"","sources":["../../src/boards/define-board.ts"],"names":[],"mappings":"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"}
|
|
@@ -168,14 +168,18 @@ function phaseEnterHandlers(declared, runner) {
|
|
|
168
168
|
return Object.keys(handlers).length > 0 ? handlers : void 0;
|
|
169
169
|
}
|
|
170
170
|
const warnedBoards = /* @__PURE__ */ new Set();
|
|
171
|
-
/**
|
|
171
|
+
/**
|
|
172
|
+
* Deprecated fields a board declaration still relies on; `defineBoard()` maps each to its
|
|
173
|
+
* replacement. A deprecated field next to its replacement adds nothing, so it is not reported:
|
|
174
|
+
* that is how a resolved board, which carries both, is declared again.
|
|
175
|
+
*/
|
|
172
176
|
function deprecatedFields(config) {
|
|
173
177
|
const found = [];
|
|
174
|
-
if (config.title !== void 0) found.push("title → name");
|
|
178
|
+
if (config.title !== void 0 && config.name === void 0) found.push("title → name");
|
|
175
179
|
for (const [phaseId, phase] of Object.entries(config.phases)) {
|
|
176
|
-
if (phase.title !== void 0) found.push(`phases.${phaseId}.title → name`);
|
|
177
|
-
if (phase.next !== void 0) found.push(`phases.${phaseId}.next → nextPhases`);
|
|
178
|
-
if (phase.role !== void 0) found.push(`phases.${phaseId}.role → runner.context`);
|
|
180
|
+
if (phase.title !== void 0 && phase.name === void 0) found.push(`phases.${phaseId}.title → name`);
|
|
181
|
+
if (phase.next !== void 0 && !phase.nextPhases?.includes(phase.next)) found.push(`phases.${phaseId}.next → nextPhases`);
|
|
182
|
+
if (phase.role !== void 0 && phase.runner?.context === void 0) found.push(`phases.${phaseId}.role → runner.context`);
|
|
179
183
|
}
|
|
180
184
|
return found;
|
|
181
185
|
}
|
|
@@ -186,7 +190,27 @@ function warnDeprecatedFields(config) {
|
|
|
186
190
|
warnedBoards.add(config.id);
|
|
187
191
|
console.warn(`[Mastra Factory] Board "${config.id}" uses deprecated fields: ${found.join(", ")}. They still work but will be removed in a future release.`);
|
|
188
192
|
}
|
|
193
|
+
/** Marks a board an app declared with the deprecated `defineBoard()`; a copy does not carry it. */
|
|
194
|
+
const DEFINED_BOARD = Symbol("DefinedBoard");
|
|
195
|
+
/**
|
|
196
|
+
* Declares a board in code.
|
|
197
|
+
*
|
|
198
|
+
* @deprecated Boards are stored per project; manage them with `/web/factory/projects/:id/boards`
|
|
199
|
+
* (README § Stored boards). Code boards are read-only and served alongside each project's stored
|
|
200
|
+
* boards.
|
|
201
|
+
*/
|
|
189
202
|
function defineBoard(config) {
|
|
203
|
+
return buildBoard(config, true);
|
|
204
|
+
}
|
|
205
|
+
/** Whether an app declared the board with the deprecated `defineBoard()`. */
|
|
206
|
+
function isDefinedBoard(board) {
|
|
207
|
+
return DEFINED_BOARD in board;
|
|
208
|
+
}
|
|
209
|
+
/** Validates and resolves a board declaration. Factory's own boards use this directly. */
|
|
210
|
+
function compileBoardDefinition(config) {
|
|
211
|
+
return buildBoard(config, false);
|
|
212
|
+
}
|
|
213
|
+
function buildBoard(config, defined) {
|
|
190
214
|
validateBoardIdentifier(config.id, "Board id");
|
|
191
215
|
const boardName = resolveName(config.name, config.title, `Board "${config.id}"`);
|
|
192
216
|
const boardDescription = optionalText(config.description, `Board "${config.id}" description`, MAX_DESCRIPTION_LENGTH);
|
|
@@ -235,11 +259,16 @@ function defineBoard(config) {
|
|
|
235
259
|
const description = optionalText(phase.description, `${label} description`, MAX_DESCRIPTION_LENGTH);
|
|
236
260
|
return [phaseId, Object.freeze({
|
|
237
261
|
name,
|
|
262
|
+
title: name,
|
|
238
263
|
...description !== void 0 ? { description } : {},
|
|
239
264
|
kind: phase.kind,
|
|
240
265
|
nextPhases,
|
|
266
|
+
...phase.next !== void 0 ? { next: phase.next } : {},
|
|
241
267
|
...phase.outcomes ? { outcomes: Object.freeze({ ...phase.outcomes }) } : {},
|
|
242
|
-
...runner ? {
|
|
268
|
+
...runner ? {
|
|
269
|
+
runner,
|
|
270
|
+
role: runner.context
|
|
271
|
+
} : {},
|
|
243
272
|
...working?.autoStart ? { autoStart: true } : {},
|
|
244
273
|
...autoStartWhen ? { autoStartWhen } : {},
|
|
245
274
|
...exitTool ? { exitTool } : {},
|
|
@@ -264,9 +293,10 @@ function defineBoard(config) {
|
|
|
264
293
|
roles.set(phaseId, phase.runner.context);
|
|
265
294
|
if (!phaseByRole.has(phase.runner.context)) phaseByRole.set(phase.runner.context, phaseId);
|
|
266
295
|
}
|
|
267
|
-
|
|
296
|
+
const board = {
|
|
268
297
|
id: config.id,
|
|
269
298
|
name: boardName,
|
|
299
|
+
title: boardName,
|
|
270
300
|
...boardDescription !== void 0 ? { description: boardDescription } : {},
|
|
271
301
|
initialPhase: config.initialPhase,
|
|
272
302
|
phases,
|
|
@@ -290,8 +320,10 @@ function defineBoard(config) {
|
|
|
290
320
|
if (!definition.autoStartWhen) return true;
|
|
291
321
|
return facts !== void 0 && evaluateRuleGroup(definition.autoStartWhen, facts);
|
|
292
322
|
}
|
|
293
|
-
}
|
|
323
|
+
};
|
|
324
|
+
if (defined) Object.defineProperty(board, DEFINED_BOARD, { value: true });
|
|
325
|
+
return Object.freeze(board);
|
|
294
326
|
}
|
|
295
|
-
export { BoardDefinitionError, DEFAULT_PHASE_CONTEXT, FACTORY_AGENT_ID, defineBoard };
|
|
327
|
+
export { BoardDefinitionError, DEFAULT_PHASE_CONTEXT, FACTORY_AGENT_ID, compileBoardDefinition, defineBoard, isDefinedBoard };
|
|
296
328
|
|
|
297
329
|
//# sourceMappingURL=define-board.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-board.js","names":[],"sources":["../../src/boards/define-board.ts"],"sourcesContent":["import { CODE_AGENT_ID } from '@mastra/code-sdk/constants';\nimport { cardRuleGroupSchema, evaluateRuleGroup } from '../rules/rule-group.js';\nimport type { RuleFacts, RuleGroup } from '../rules/rule-group.js';\nimport {\n FACTORY_GITHUB_EVENTS,\n FACTORY_RULE_SOURCES,\n FACTORY_GITLAB_EVENTS,\n FACTORY_INCIDENTIO_EVENTS,\n FACTORY_JIRA_EVENTS,\n FACTORY_LINEAR_EVENTS,\n} from '../rules/types.js';\nimport type {\n FactoryGithubEventName,\n FactoryGithubRuleContext,\n FactoryGitLabEventName,\n FactoryGitLabRuleContext,\n FactoryIncidentioEventName,\n FactoryIncidentioRuleContext,\n FactoryJiraEventName,\n FactoryJiraRuleContext,\n FactoryLinearEventName,\n FactoryLinearRuleContext,\n FactoryRuleHandler,\n FactoryRuleSource,\n FactoryStageRuleContext,\n FactoryToolResultRuleContext,\n} from '../rules/types.js';\nimport {\n IDENTIFIER_RE,\n isBoardIdentifier,\n MAX_ROLE_LENGTH,\n MAX_SKILL_NAME_LENGTH,\n MAX_TOOL_NAME_LENGTH,\n SKILL_NAME_RE,\n} from '../rules/validation.js';\nimport { addInstructions, startSkill } from './phase-runner.js';\nimport type { BoardTransitionPolicy } from './transition-policy.js';\n\ntype BoardPhaseHandlers = Partial<Record<FactoryRuleSource, FactoryRuleHandler<FactoryStageRuleContext>>>;\ntype ReadonlyBoardPhaseHandlers = Readonly<BoardPhaseHandlers>;\n\n/** Runs when an agent seated on this board completes the named tool. */\nexport type BoardToolResultRuleHandler = FactoryRuleHandler<FactoryToolResultRuleContext>;\nexport type BoardToolRule = { readonly onResult: BoardToolResultRuleHandler };\nexport type BoardToolRules = Readonly<Record<string, BoardToolRule>>;\n\n/**\n * A board's handler for one integration event. `null` switches the integration default off\n * for cards on this board only.\n */\ntype BoardEventHandlerMap<EventName extends string, Context> = Readonly<\n Partial<Record<EventName, FactoryRuleHandler<Context> | null>>\n>;\n\n/**\n * How cards on this board react to integration events, keyed by integration then event.\n * Consulted for events bound to a card on this board, after any handler the deployment set\n * explicitly on the integration and before the integration default.\n */\nexport interface BoardEventRules {\n readonly github?: BoardEventHandlerMap<FactoryGithubEventName, FactoryGithubRuleContext>;\n readonly gitlab?: BoardEventHandlerMap<FactoryGitLabEventName, FactoryGitLabRuleContext>;\n readonly linear?: BoardEventHandlerMap<FactoryLinearEventName, FactoryLinearRuleContext>;\n readonly jira?: BoardEventHandlerMap<FactoryJiraEventName, FactoryJiraRuleContext>;\n readonly incidentio?: BoardEventHandlerMap<FactoryIncidentioEventName, FactoryIncidentioRuleContext>;\n}\nexport type BoardEventIntegration = keyof BoardEventRules;\n\nconst BOARD_EVENT_NAMES: Readonly<Record<BoardEventIntegration, readonly string[]>> = {\n github: FACTORY_GITHUB_EVENTS,\n gitlab: FACTORY_GITLAB_EVENTS,\n linear: FACTORY_LINEAR_EVENTS,\n jira: FACTORY_JIRA_EVENTS,\n incidentio: FACTORY_INCIDENTIO_EVENTS,\n};\n\ntype ReadonlyFactoryBoardRules = Readonly<\n Record<\n string,\n Readonly<\n Partial<\n Record<\n FactoryRuleSource,\n Readonly<{\n onEnter?: FactoryRuleHandler<FactoryStageRuleContext>;\n onExit?: FactoryRuleHandler<FactoryStageRuleContext>;\n }>\n >\n >\n >\n >\n>;\n\n/**\n * What a phase means to the runtime.\n * - `resting`: nobody is seated; a card waits for a person or an event.\n * - `working`: an agent in the phase's context carries the card; a person's move in arms autonomy.\n * - `terminal`: the card is finished; sessions stop and held resources are released.\n */\nexport type BoardPhaseKind = 'resting' | 'working' | 'terminal';\n\n/** The agent Factory runs every phase with. */\nexport const FACTORY_AGENT_ID = CODE_AGENT_ID;\n\n/** The session context a working phase runs in when it names none. */\nexport const DEFAULT_PHASE_CONTEXT = 'work';\n\n/** Who runs a working phase, and with what. */\nexport interface BoardPhaseRunner {\n /** Must be `code-agent`, the agent Factory runs; omitted means that agent. */\n readonly agentId?: string;\n /** Skill started when a card enters the phase from a source with no `onEnter` handler. */\n readonly skill?: string;\n /**\n * The session the phase runs in. Phases naming the same context share one session per card;\n * a different context gets its own. Defaults to `work`.\n */\n readonly context?: string;\n /** Appended to every run the phase starts. */\n readonly instructions?: string;\n}\n\n/**\n * The tool whose successful call ends a working phase. The agent then moves the card itself with\n * `factory_transition_work_item`, to one of the phase's `nextPhases`.\n */\nexport interface BoardPhaseExitTool {\n readonly id: string;\n /**\n * Answer the approval the tool waits for without a person. Factory sessions run other tools\n * without asking, so today this applies to `submit_plan`. Defaults to false.\n */\n readonly autoApprove?: boolean;\n /** With `autoApprove`, only cards this matches are approved without a person. */\n readonly autoApproveWhen?: RuleGroup;\n}\n\ntype BoardPhaseBase<PhaseId extends string> = {\n readonly name?: string;\n /** @deprecated Use `name`. */\n readonly title?: string;\n readonly description?: string;\n /** Phases a card may move to from here. */\n readonly nextPhases?: readonly PhaseId[];\n /** @deprecated List the phase in `nextPhases`. */\n readonly next?: PhaseId;\n /** Named moves rules can choose by outcome; each target is also an allowed next phase. */\n readonly outcomes?: Readonly<Record<string, PhaseId>>;\n readonly onEnter?: ReadonlyBoardPhaseHandlers;\n readonly onExit?: ReadonlyBoardPhaseHandlers;\n};\n\ntype WorkingPhaseFields = {\n readonly runner?: BoardPhaseRunner;\n /** @deprecated Use `runner.context`. */\n readonly role?: string;\n /** Runs start without anyone approving them, even with the project's auto-run off. */\n readonly autoStart?: boolean;\n /** With `autoStart`, only cards this matches start on their own. */\n readonly autoStartWhen?: RuleGroup;\n /** A bare tool name is shorthand for `{ id }`, with nothing approved on a person's behalf. */\n readonly exitTool?: string | BoardPhaseExitTool;\n};\n\ntype NonWorkingPhaseFields = {\n readonly runner?: never;\n readonly role?: never;\n readonly autoStart?: never;\n readonly autoStartWhen?: never;\n readonly exitTool?: never;\n};\n\n/** A phase as a board declares it. */\nexport type BoardPhaseDefinition<PhaseId extends string> =\n | (BoardPhaseBase<PhaseId> & NonWorkingPhaseFields & { readonly kind: 'resting' })\n | (BoardPhaseBase<PhaseId> & WorkingPhaseFields & { readonly kind: 'working' })\n | (BoardPhaseBase<PhaseId> & NonWorkingPhaseFields & { readonly kind: 'terminal' });\n\ntype ResolvedPhaseBase<PhaseId extends string> = {\n readonly name: string;\n readonly description?: string;\n /** Every phase a card may move to from here, including outcome targets. */\n readonly nextPhases: readonly PhaseId[];\n readonly outcomes?: Readonly<Record<string, PhaseId>>;\n readonly onEnter?: ReadonlyBoardPhaseHandlers;\n readonly onExit?: ReadonlyBoardPhaseHandlers;\n};\n\n/**\n * A phase as the board resolved it: deprecated fields are replaced by their new names, so\n * only the new structure leaves `defineBoard()`, and a resolved phase can be declared again.\n */\nexport type BoardPhase<PhaseId extends string> =\n | (ResolvedPhaseBase<PhaseId> & { readonly kind: 'resting' })\n | (ResolvedPhaseBase<PhaseId> & {\n readonly kind: 'working';\n readonly runner: Readonly<BoardPhaseRunner & { agentId: string; context: string }>;\n readonly autoStart?: boolean;\n readonly autoStartWhen?: RuleGroup;\n readonly exitTool?: Readonly<{ id: string; autoApprove: boolean; autoApproveWhen?: RuleGroup }>;\n })\n | (ResolvedPhaseBase<PhaseId> & { readonly kind: 'terminal' });\n\ntype ResolvedRunner = Extract<BoardPhase<string>, { kind: 'working' }>['runner'];\ntype ResolvedExitTool = Extract<BoardPhase<string>, { kind: 'working' }>['exitTool'];\n\nexport interface BoardTransition<PhaseId extends string> {\n readonly outcome: string | null;\n readonly to: PhaseId;\n}\n\n/**\n * Terminal phases a card moves to when its tracked source (issue or follow-up) closes.\n * `completed` is used when the source was completed, `canceled` when it was canceled or not planned.\n */\nexport type BoardSourceClosed<PhaseId extends string> = Readonly<{ completed: PhaseId; canceled: PhaseId }>;\n\nexport interface BoardDefinition<BoardId extends string, PhaseId extends string> {\n readonly id: BoardId;\n readonly name: string;\n readonly description?: string;\n readonly initialPhase: PhaseId;\n readonly phases: Readonly<Record<PhaseId, BoardPhase<PhaseId>>>;\n readonly transitions: Readonly<Record<PhaseId, readonly BoardTransition<PhaseId>[]>>;\n readonly rules: ReadonlyFactoryBoardRules;\n /** Tool-result rules keyed by tool name; empty when the board declares none. */\n readonly tools: BoardToolRules;\n /** Integration event handlers for cards on this board; empty when the board declares none. */\n readonly events: BoardEventRules;\n readonly transitionPolicy?: BoardTransitionPolicy;\n /** Where source-closed rules move a card; absent when the board opts out of auto-closing. */\n readonly sourceClosed?: BoardSourceClosed<PhaseId>;\n allowsTransition(from: PhaseId, to: PhaseId): boolean;\n /** Declared kind of a phase, or undefined when the board has no such phase. */\n phaseKind(phase: string): BoardPhaseKind | undefined;\n isWorking(phase: string): boolean;\n isTerminal(phase: string): boolean;\n /** Session context of a working phase; undefined for resting/terminal/unknown phases. */\n roleForPhase(phase: string): string | undefined;\n /** First working phase, in declaration order, running in `role`'s context. */\n phaseForRole(role: string): PhaseId | undefined;\n /**\n * Whether the phase's runs start without anyone approving them, for a card with these facts\n * (`cardRuleFacts`). A phase with a start condition never starts on its own without facts.\n */\n startsAutomatically(phase: string, facts?: RuleFacts): boolean;\n}\n\ntype BoardConfig<BoardId extends string, Phases extends Record<string, BoardPhaseDefinition<keyof Phases & string>>> = {\n id: BoardId;\n name?: string;\n /** @deprecated Use `name`. */\n title?: string;\n description?: string;\n initialPhase: keyof Phases & string;\n phases: Phases;\n tools?: Record<string, BoardToolRule>;\n events?: BoardEventRules;\n transitionPolicy?: BoardTransitionPolicy;\n sourceClosed?: { completed: keyof Phases & string; canceled: keyof Phases & string };\n};\n\nexport class BoardDefinitionError extends Error {\n override name = 'BoardDefinitionError';\n}\n\nconst PHASE_KINDS: ReadonlySet<string> = new Set<BoardPhaseKind>(['resting', 'working', 'terminal']);\n\nfunction validateBoardIdentifier(value: unknown, label: string): void {\n if (!isBoardIdentifier(value)) {\n throw new BoardDefinitionError(`${label} must be a valid board identifier.`);\n }\n}\n\nconst MAX_NAME_LENGTH = 128;\nconst MAX_DESCRIPTION_LENGTH = 2_000;\nconst MAX_INSTRUCTIONS_LENGTH = 1_000;\nconst RUNNER_KEYS: ReadonlySet<string> = new Set(['agentId', 'skill', 'context', 'instructions']);\nconst EXIT_TOOL_KEYS: ReadonlySet<string> = new Set(['id', 'autoApprove', 'autoApproveWhen']);\nconst WORKING_ONLY_FIELDS = ['runner', 'autoStart', 'autoStartWhen', 'exitTool'] as const;\nconst MOVE_TOOL = 'factory_transition_work_item';\n\n/** `name`, falling back to the deprecated `title`; both may be set only to the same text. */\nfunction resolveName(name: unknown, title: unknown, label: string): string {\n if (name !== undefined && title !== undefined && name !== title) {\n throw new BoardDefinitionError(`${label} sets both name and title; drop the deprecated title.`);\n }\n const value = name ?? title;\n if (typeof value !== 'string' || value.trim().length === 0 || value.length > MAX_NAME_LENGTH) {\n throw new BoardDefinitionError(`${label} must declare a name.`);\n }\n return value;\n}\n\nfunction optionalText(value: unknown, label: string, max: number): string | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'string' || value.trim().length === 0 || value.length > max) {\n throw new BoardDefinitionError(`${label} must be non-empty text of at most ${max} characters.`);\n }\n return value;\n}\n\nfunction ruleGroup(value: unknown, label: string): RuleGroup | undefined {\n if (value === undefined) return undefined;\n const parsed = cardRuleGroupSchema.safeParse(value);\n if (!parsed.success) {\n throw new BoardDefinitionError(`${label} is not a valid condition: ${parsed.error.issues[0]?.message}`);\n }\n return parsed.data;\n}\n\nfunction isContext(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0 && value.length <= MAX_ROLE_LENGTH && IDENTIFIER_RE.test(value);\n}\n\nfunction resolveRunner(phaseId: string, phase: BoardPhaseDefinition<string>): ResolvedRunner {\n const runner: unknown = phase.runner ?? {};\n if (!isPlainObject(runner) || Object.keys(runner).some(key => !RUNNER_KEYS.has(key))) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" runner may only set agentId, skill, context and instructions.`);\n }\n const role: unknown = phase.role;\n if (role !== undefined && runner.context !== undefined && role !== runner.context) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" sets both role and runner.context; drop the deprecated role.`);\n }\n const context = runner.context ?? role ?? DEFAULT_PHASE_CONTEXT;\n if (!isContext(context)) throw new BoardDefinitionError(`Working phase \"${phaseId}\" must declare a valid context.`);\n const agentId = runner.agentId ?? FACTORY_AGENT_ID;\n if (agentId !== FACTORY_AGENT_ID) {\n throw new BoardDefinitionError(\n `Phase \"${phaseId}\" names unknown agent \"${String(agentId)}\"; Factory runs \"${FACTORY_AGENT_ID}\".`,\n );\n }\n const skill = runner.skill;\n if (\n skill !== undefined &&\n (typeof skill !== 'string' || skill.length > MAX_SKILL_NAME_LENGTH || !SKILL_NAME_RE.test(skill))\n ) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" runner.skill must be a skill name.`);\n }\n const instructions = optionalText(\n runner.instructions,\n `Phase \"${phaseId}\" runner.instructions`,\n MAX_INSTRUCTIONS_LENGTH,\n );\n return Object.freeze({\n agentId,\n context,\n ...(skill !== undefined ? { skill } : {}),\n ...(instructions !== undefined ? { instructions } : {}),\n });\n}\n\nfunction resolveExitTool(phaseId: string, value: unknown): ResolvedExitTool {\n if (value === undefined) return undefined;\n const declared = typeof value === 'string' ? { id: value } : value;\n if (!isPlainObject(declared) || Object.keys(declared).some(key => !EXIT_TOOL_KEYS.has(key))) {\n throw new BoardDefinitionError(\n `Phase \"${phaseId}\" exitTool must be a tool name or { id, autoApprove, autoApproveWhen }.`,\n );\n }\n const { id, autoApprove = false } = declared;\n if (typeof id !== 'string' || id.length === 0 || id.length > MAX_TOOL_NAME_LENGTH || !IDENTIFIER_RE.test(id)) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" exitTool has an invalid tool name.`);\n }\n if (id === MOVE_TOOL) {\n throw new BoardDefinitionError(\n `Phase \"${phaseId}\" cannot end with ${MOVE_TOOL}: that tool already moves the card.`,\n );\n }\n if (typeof autoApprove !== 'boolean') {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" exitTool.autoApprove must be a boolean.`);\n }\n const autoApproveWhen = ruleGroup(declared.autoApproveWhen, `Phase \"${phaseId}\" exitTool.autoApproveWhen`);\n if (autoApproveWhen && !autoApprove) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" exitTool.autoApproveWhen needs autoApprove.`);\n }\n return Object.freeze({ id, autoApprove, ...(autoApproveWhen ? { autoApproveWhen } : {}) });\n}\n\nfunction validatePhaseSemantics(phaseId: string, phase: BoardPhaseDefinition<string>): void {\n if (!PHASE_KINDS.has(phase.kind as string)) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" must declare kind 'resting', 'working', or 'terminal'.`);\n }\n if (phase.kind === 'working') return;\n if ((phase as { role?: unknown }).role !== undefined) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" is ${phase.kind} and cannot declare a role.`);\n }\n for (const field of WORKING_ONLY_FIELDS) {\n if ((phase as Record<string, unknown>)[field] !== undefined) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" is ${phase.kind} and cannot declare ${field}.`);\n }\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 validateToolRules(tools: unknown): BoardToolRules {\n if (tools === undefined) return Object.freeze({});\n if (!isPlainObject(tools)) throw new BoardDefinitionError('Board tools must be a plain object.');\n const frozen: Record<string, BoardToolRule> = {};\n for (const [toolName, leaf] of Object.entries(tools)) {\n if (toolName.length === 0 || toolName.length > MAX_TOOL_NAME_LENGTH || !IDENTIFIER_RE.test(toolName)) {\n throw new BoardDefinitionError(`Tool rule \"${toolName}\" has an invalid tool name.`);\n }\n if (!isPlainObject(leaf) || Object.keys(leaf).some(key => key !== 'onResult')) {\n throw new BoardDefinitionError(`Tool rule \"${toolName}\" must be an object with only onResult.`);\n }\n if (typeof leaf.onResult !== 'function') {\n throw new BoardDefinitionError(`Tool rule \"${toolName}\" must declare an onResult function.`);\n }\n frozen[toolName] = Object.freeze({ onResult: leaf.onResult as BoardToolResultRuleHandler });\n }\n return Object.freeze(frozen);\n}\n\nfunction validateSourceClosed(\n sourceClosed: unknown,\n phases: Readonly<Record<string, BoardPhaseDefinition<string>>>,\n): BoardSourceClosed<string> | undefined {\n if (sourceClosed === undefined) return undefined;\n if (!isPlainObject(sourceClosed)) throw new BoardDefinitionError('Board sourceClosed must be a plain object.');\n const keys = Object.keys(sourceClosed);\n if (keys.length !== 2 || !keys.includes('completed') || !keys.includes('canceled')) {\n throw new BoardDefinitionError('Board sourceClosed must declare exactly completed and canceled.');\n }\n for (const key of ['completed', 'canceled'] as const) {\n const phase = sourceClosed[key];\n if (typeof phase !== 'string' || !Object.hasOwn(phases, phase) || phases[phase]!.kind !== 'terminal') {\n throw new BoardDefinitionError(`Board sourceClosed.${key} \"${String(phase)}\" must name a terminal phase.`);\n }\n }\n return Object.freeze({ completed: sourceClosed.completed as string, canceled: sourceClosed.canceled as string });\n}\n\nfunction validateEventRules(events: unknown): BoardEventRules {\n if (events === undefined) return Object.freeze({});\n if (!isPlainObject(events)) throw new BoardDefinitionError('Board events must be a plain object.');\n const frozen: Record<string, Readonly<Record<string, unknown>>> = {};\n for (const [integration, handlers] of Object.entries(events)) {\n const known = Object.hasOwn(BOARD_EVENT_NAMES, integration)\n ? BOARD_EVENT_NAMES[integration as BoardEventIntegration]\n : undefined;\n if (!known) throw new BoardDefinitionError(`Board events name unknown integration \"${integration}\".`);\n if (handlers === undefined) continue;\n if (!isPlainObject(handlers)) {\n throw new BoardDefinitionError(`Board events for \"${integration}\" must be a plain object.`);\n }\n const entries: Record<string, unknown> = {};\n for (const [event, handler] of Object.entries(handlers)) {\n if (!known.includes(event)) {\n throw new BoardDefinitionError(`Board events for \"${integration}\" name unknown event \"${event}\".`);\n }\n if (handler === undefined) continue;\n if (handler !== null && typeof handler !== 'function') {\n throw new BoardDefinitionError(`Board event handler \"${integration}.${event}\" must be a function or null.`);\n }\n entries[event] = handler;\n }\n frozen[integration] = Object.freeze(entries);\n }\n return Object.freeze(frozen) as BoardEventRules;\n}\n\n/** The phase's `onEnter` handlers, with its runner's skill for other sources and its instructions on every run. */\nfunction phaseEnterHandlers(\n declared: ReadonlyBoardPhaseHandlers | undefined,\n runner: ResolvedRunner,\n): ReadonlyBoardPhaseHandlers | undefined {\n const handlers: BoardPhaseHandlers = { ...declared };\n if (runner.skill) {\n for (const source of FACTORY_RULE_SOURCES) handlers[source] ??= startSkill(runner.skill, runner.context);\n }\n if (runner.instructions) {\n for (const source of Object.keys(handlers) as FactoryRuleSource[]) {\n handlers[source] = addInstructions(handlers[source]!, runner.instructions);\n }\n }\n return Object.keys(handlers).length > 0 ? handlers : undefined;\n}\n\nconst warnedBoards = new Set<string>();\n\ntype DeclaredBoard = {\n readonly id: string;\n readonly name?: string;\n readonly title?: string;\n readonly phases: Readonly<Record<string, BoardPhaseDefinition<string>>>;\n};\n\n/** Deprecated fields a board declaration still uses; `defineBoard()` maps each to its replacement. */\nfunction deprecatedFields(config: DeclaredBoard): string[] {\n const found: string[] = [];\n if (config.title !== undefined) found.push('title → name');\n for (const [phaseId, phase] of Object.entries(config.phases)) {\n if (phase.title !== undefined) found.push(`phases.${phaseId}.title → name`);\n if (phase.next !== undefined) found.push(`phases.${phaseId}.next → nextPhases`);\n if (phase.role !== undefined) found.push(`phases.${phaseId}.role → runner.context`);\n }\n return found;\n}\n\nfunction warnDeprecatedFields(config: DeclaredBoard): void {\n if (warnedBoards.has(config.id)) return;\n const found = deprecatedFields(config);\n if (found.length === 0) return;\n warnedBoards.add(config.id);\n console.warn(\n `[Mastra Factory] Board \"${config.id}\" uses deprecated fields: ${found.join(', ')}. ` +\n 'They still work but will be removed in a future release.',\n );\n}\n\nexport function defineBoard<\n const BoardId extends string,\n const Phases extends Record<string, BoardPhaseDefinition<keyof Phases & string>>,\n>(config: BoardConfig<BoardId, Phases>): BoardDefinition<BoardId, keyof Phases & string> {\n type PhaseId = keyof Phases & string;\n validateBoardIdentifier(config.id, 'Board id');\n const boardName = resolveName(config.name, config.title, `Board \"${config.id}\"`);\n const boardDescription = optionalText(config.description, `Board \"${config.id}\" description`, MAX_DESCRIPTION_LENGTH);\n if (config.transitionPolicy !== undefined && typeof config.transitionPolicy !== 'function') {\n throw new BoardDefinitionError('Board transitionPolicy must be a function.');\n }\n const tools = validateToolRules(config.tools);\n const events = validateEventRules(config.events);\n const phaseIds = new Set(Object.keys(config.phases));\n if (phaseIds.size === 0) throw new BoardDefinitionError('A board must define at least one phase.');\n if (!phaseIds.has(config.initialPhase)) {\n throw new BoardDefinitionError(`Initial phase \"${config.initialPhase}\" is not defined.`);\n }\n for (const [phaseId, phase] of Object.entries(config.phases)) {\n validateBoardIdentifier(phaseId, 'Phase id');\n validatePhaseSemantics(phaseId, phase);\n }\n if (config.phases[config.initialPhase]!.kind !== 'resting') {\n throw new BoardDefinitionError(`Initial phase \"${config.initialPhase}\" must be a resting phase.`);\n }\n warnDeprecatedFields(config);\n const sourceClosed = validateSourceClosed(config.sourceClosed, config.phases) as\n | BoardSourceClosed<PhaseId>\n | undefined;\n\n const transitions = Object.fromEntries(\n Object.entries(config.phases).map(([phaseId, phase]) => {\n if (phase.next !== undefined && phase.outcomes) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" cannot define both next and outcomes.`);\n }\n if (phase.nextPhases !== undefined && !Array.isArray(phase.nextPhases)) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" nextPhases must be a list of phases.`);\n }\n const targets: BoardTransition<string>[] =\n phase.next !== undefined\n ? [Object.freeze({ outcome: null, to: phase.next })]\n : Object.entries(phase.outcomes ?? {}).map(([outcome, to]) => Object.freeze({ outcome, to }));\n for (const to of phase.nextPhases ?? []) {\n if (!targets.some(target => target.to === to)) targets.push(Object.freeze({ outcome: null, to }));\n }\n for (const { to } of targets) {\n if (!phaseIds.has(to)) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" targets undefined phase \"${to}\".`);\n }\n }\n return [phaseId, Object.freeze(targets)];\n }),\n ) as Record<PhaseId, readonly BoardTransition<PhaseId>[]>;\n\n const phases = Object.freeze(\n Object.fromEntries(\n Object.entries(config.phases).map(([phaseId, phase]) => {\n const label = `Phase \"${phaseId}\"`;\n const nextPhases = Object.freeze([\n ...new Set([...(phase.nextPhases ?? []), ...transitions[phaseId as PhaseId]!.map(({ to }) => to)]),\n ]);\n const runner = phase.kind === 'working' ? resolveRunner(phaseId, phase) : undefined;\n const working = phase.kind === 'working' ? phase : undefined;\n if (working?.autoStart !== undefined && typeof working.autoStart !== 'boolean') {\n throw new BoardDefinitionError(`${label} autoStart must be a boolean.`);\n }\n const autoStartWhen = ruleGroup(working?.autoStartWhen, `${label} autoStartWhen`);\n if (autoStartWhen && working?.autoStart !== true) {\n throw new BoardDefinitionError(`${label} autoStartWhen needs autoStart.`);\n }\n const exitTool = resolveExitTool(phaseId, working?.exitTool);\n if (exitTool && nextPhases.length === 0) {\n throw new BoardDefinitionError(`${label} exit tool needs a next phase to move the card to.`);\n }\n const onEnter = runner ? phaseEnterHandlers(phase.onEnter, runner) : phase.onEnter;\n const name = resolveName(phase.name, phase.title, label);\n const description = optionalText(phase.description, `${label} description`, MAX_DESCRIPTION_LENGTH);\n return [\n phaseId,\n Object.freeze({\n name,\n ...(description !== undefined ? { description } : {}),\n kind: phase.kind,\n nextPhases,\n ...(phase.outcomes ? { outcomes: Object.freeze({ ...phase.outcomes }) } : {}),\n ...(runner ? { runner } : {}),\n ...(working?.autoStart ? { autoStart: true } : {}),\n ...(autoStartWhen ? { autoStartWhen } : {}),\n ...(exitTool ? { exitTool } : {}),\n ...(onEnter ? { onEnter: Object.freeze({ ...onEnter }) } : {}),\n ...(phase.onExit ? { onExit: Object.freeze({ ...phase.onExit }) } : {}),\n }),\n ];\n }),\n ),\n ) as Readonly<Record<PhaseId, BoardPhase<PhaseId>>>;\n const rules = Object.freeze(\n Object.fromEntries(\n (Object.entries(phases) as [PhaseId, BoardPhase<PhaseId>][]).flatMap(([phaseId, phase]) => {\n const sources = new Set([...Object.keys(phase.onEnter ?? {}), ...Object.keys(phase.onExit ?? {})]);\n if (sources.size === 0) return [];\n return [\n [\n phaseId,\n Object.freeze(\n Object.fromEntries(\n [...sources].map(source => [\n source,\n Object.freeze({\n ...(phase.onEnter?.[source as FactoryRuleSource]\n ? { onEnter: phase.onEnter[source as FactoryRuleSource] }\n : {}),\n ...(phase.onExit?.[source as FactoryRuleSource]\n ? { onExit: phase.onExit[source as FactoryRuleSource] }\n : {}),\n }),\n ]),\n ),\n ),\n ],\n ];\n }),\n ),\n ) as ReadonlyFactoryBoardRules;\n\n const kinds = new Map<string, BoardPhaseKind>();\n const roles = new Map<string, string>();\n const phaseByRole = new Map<string, PhaseId>();\n for (const [phaseId, phase] of Object.entries(phases) as [PhaseId, BoardPhase<PhaseId>][]) {\n kinds.set(phaseId, phase.kind);\n if (phase.kind !== 'working') continue;\n roles.set(phaseId, phase.runner.context);\n if (!phaseByRole.has(phase.runner.context)) phaseByRole.set(phase.runner.context, phaseId);\n }\n\n return Object.freeze({\n id: config.id,\n name: boardName,\n ...(boardDescription !== undefined ? { description: boardDescription } : {}),\n initialPhase: config.initialPhase,\n phases,\n transitions: Object.freeze(transitions),\n rules: Object.freeze(rules),\n tools,\n events,\n ...(config.transitionPolicy ? { transitionPolicy: config.transitionPolicy } : {}),\n ...(sourceClosed ? { sourceClosed } : {}),\n allowsTransition(from: PhaseId, to: PhaseId) {\n return from === to || transitions[from]?.some(transition => transition.to === to) === true;\n },\n phaseKind: (phase: string) => kinds.get(phase),\n isWorking: (phase: string) => kinds.get(phase) === 'working',\n isTerminal: (phase: string) => kinds.get(phase) === 'terminal',\n roleForPhase: (phase: string) => roles.get(phase),\n phaseForRole: (role: string) => phaseByRole.get(role),\n startsAutomatically: (phase: string, facts?: RuleFacts) => {\n const definition = phases[phase as PhaseId] as BoardPhase<PhaseId> | undefined;\n if (definition?.kind !== 'working' || definition.autoStart !== true) return false;\n if (!definition.autoStartWhen) return true;\n return facts !== undefined && evaluateRuleGroup(definition.autoStartWhen, facts);\n },\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"define-board.js","names":[],"sources":["../../src/boards/define-board.ts"],"sourcesContent":["import { CODE_AGENT_ID } from '@mastra/code-sdk/constants';\nimport { cardRuleGroupSchema, evaluateRuleGroup } from '../rules/rule-group.js';\nimport type { RuleFacts, RuleGroup } from '../rules/rule-group.js';\nimport {\n FACTORY_GITHUB_EVENTS,\n FACTORY_RULE_SOURCES,\n FACTORY_GITLAB_EVENTS,\n FACTORY_INCIDENTIO_EVENTS,\n FACTORY_JIRA_EVENTS,\n FACTORY_LINEAR_EVENTS,\n} from '../rules/types.js';\nimport type {\n FactoryGithubEventName,\n FactoryGithubRuleContext,\n FactoryGitLabEventName,\n FactoryGitLabRuleContext,\n FactoryIncidentioEventName,\n FactoryIncidentioRuleContext,\n FactoryJiraEventName,\n FactoryJiraRuleContext,\n FactoryLinearEventName,\n FactoryLinearRuleContext,\n FactoryRuleHandler,\n FactoryRuleSource,\n FactoryStageRuleContext,\n FactoryToolResultRuleContext,\n} from '../rules/types.js';\nimport {\n IDENTIFIER_RE,\n isBoardIdentifier,\n MAX_ROLE_LENGTH,\n MAX_SKILL_NAME_LENGTH,\n MAX_TOOL_NAME_LENGTH,\n SKILL_NAME_RE,\n} from '../rules/validation.js';\nimport { addInstructions, startSkill } from './phase-runner.js';\nimport type { BoardTransitionPolicy } from './transition-policy.js';\n\ntype BoardPhaseHandlers = Partial<Record<FactoryRuleSource, FactoryRuleHandler<FactoryStageRuleContext>>>;\ntype ReadonlyBoardPhaseHandlers = Readonly<BoardPhaseHandlers>;\n\n/** Runs when an agent seated on this board completes the named tool. */\nexport type BoardToolResultRuleHandler = FactoryRuleHandler<FactoryToolResultRuleContext>;\nexport type BoardToolRule = { readonly onResult: BoardToolResultRuleHandler };\nexport type BoardToolRules = Readonly<Record<string, BoardToolRule>>;\n\n/**\n * A board's handler for one integration event. `null` switches the integration default off\n * for cards on this board only.\n */\ntype BoardEventHandlerMap<EventName extends string, Context> = Readonly<\n Partial<Record<EventName, FactoryRuleHandler<Context> | null>>\n>;\n\n/**\n * How cards on this board react to integration events, keyed by integration then event.\n * Consulted for events bound to a card on this board, after any handler the deployment set\n * explicitly on the integration and before the integration default.\n */\nexport interface BoardEventRules {\n readonly github?: BoardEventHandlerMap<FactoryGithubEventName, FactoryGithubRuleContext>;\n readonly gitlab?: BoardEventHandlerMap<FactoryGitLabEventName, FactoryGitLabRuleContext>;\n readonly linear?: BoardEventHandlerMap<FactoryLinearEventName, FactoryLinearRuleContext>;\n readonly jira?: BoardEventHandlerMap<FactoryJiraEventName, FactoryJiraRuleContext>;\n readonly incidentio?: BoardEventHandlerMap<FactoryIncidentioEventName, FactoryIncidentioRuleContext>;\n}\nexport type BoardEventIntegration = keyof BoardEventRules;\n\nconst BOARD_EVENT_NAMES: Readonly<Record<BoardEventIntegration, readonly string[]>> = {\n github: FACTORY_GITHUB_EVENTS,\n gitlab: FACTORY_GITLAB_EVENTS,\n linear: FACTORY_LINEAR_EVENTS,\n jira: FACTORY_JIRA_EVENTS,\n incidentio: FACTORY_INCIDENTIO_EVENTS,\n};\n\ntype ReadonlyFactoryBoardRules = Readonly<\n Record<\n string,\n Readonly<\n Partial<\n Record<\n FactoryRuleSource,\n Readonly<{\n onEnter?: FactoryRuleHandler<FactoryStageRuleContext>;\n onExit?: FactoryRuleHandler<FactoryStageRuleContext>;\n }>\n >\n >\n >\n >\n>;\n\n/**\n * What a phase means to the runtime.\n * - `resting`: nobody is seated; a card waits for a person or an event.\n * - `working`: an agent in the phase's context carries the card; a person's move in arms autonomy.\n * - `terminal`: the card is finished; sessions stop and held resources are released.\n */\nexport type BoardPhaseKind = 'resting' | 'working' | 'terminal';\n\n/** The agent Factory runs every phase with. */\nexport const FACTORY_AGENT_ID = CODE_AGENT_ID;\n\n/** The session context a working phase runs in when it names none. */\nexport const DEFAULT_PHASE_CONTEXT = 'work';\n\n/** Who runs a working phase, and with what. */\nexport interface BoardPhaseRunner {\n /** Must be `code-agent`, the agent Factory runs; omitted means that agent. */\n readonly agentId?: string;\n /** Skill started when a card enters the phase from a source with no `onEnter` handler. */\n readonly skill?: string;\n /**\n * The session the phase runs in. Phases naming the same context share one session per card;\n * a different context gets its own. Defaults to `work`.\n */\n readonly context?: string;\n /** Appended to every run the phase starts. */\n readonly instructions?: string;\n}\n\n/**\n * The tool whose successful call ends a working phase. The agent then moves the card itself with\n * `factory_transition_work_item`, to one of the phase's `nextPhases`.\n */\nexport interface BoardPhaseExitTool {\n readonly id: string;\n /**\n * Answer the approval the tool waits for without a person. Factory sessions run other tools\n * without asking, so today this applies to `submit_plan`. Defaults to false.\n */\n readonly autoApprove?: boolean;\n /** With `autoApprove`, only cards this matches are approved without a person. */\n readonly autoApproveWhen?: RuleGroup;\n}\n\ntype BoardPhaseBase<PhaseId extends string> = {\n readonly name?: string;\n /** @deprecated Use `name`. */\n readonly title?: string;\n readonly description?: string;\n /** Phases a card may move to from here. */\n readonly nextPhases?: readonly PhaseId[];\n /** @deprecated List the phase in `nextPhases`. */\n readonly next?: PhaseId;\n /** Named moves rules can choose by outcome; each target is also an allowed next phase. */\n readonly outcomes?: Readonly<Record<string, PhaseId>>;\n readonly onEnter?: ReadonlyBoardPhaseHandlers;\n readonly onExit?: ReadonlyBoardPhaseHandlers;\n};\n\ntype WorkingPhaseFields = {\n readonly runner?: BoardPhaseRunner;\n /** @deprecated Use `runner.context`. */\n readonly role?: string;\n /** Runs start without anyone approving them, even with the project's auto-run off. */\n readonly autoStart?: boolean;\n /** With `autoStart`, only cards this matches start on their own. */\n readonly autoStartWhen?: RuleGroup;\n /** A bare tool name is shorthand for `{ id }`, with nothing approved on a person's behalf. */\n readonly exitTool?: string | BoardPhaseExitTool;\n};\n\ntype NonWorkingPhaseFields = {\n readonly runner?: never;\n readonly role?: never;\n readonly autoStart?: never;\n readonly autoStartWhen?: never;\n readonly exitTool?: never;\n};\n\n/** A phase as a board declares it. */\nexport type BoardPhaseDefinition<PhaseId extends string> =\n | (BoardPhaseBase<PhaseId> & NonWorkingPhaseFields & { readonly kind: 'resting' })\n | (BoardPhaseBase<PhaseId> & WorkingPhaseFields & { readonly kind: 'working' })\n | (BoardPhaseBase<PhaseId> & NonWorkingPhaseFields & { readonly kind: 'terminal' });\n\ntype ResolvedPhaseBase<PhaseId extends string> = {\n readonly name: string;\n /** @deprecated Use `name`; kept equal to it for code written against older Factory versions. */\n readonly title: string;\n readonly description?: string;\n /** Every phase a card may move to from here, including outcome targets. */\n readonly nextPhases: readonly PhaseId[];\n /** @deprecated Use `nextPhases`; set when the phase declared `next`. */\n readonly next?: PhaseId;\n readonly outcomes?: Readonly<Record<string, PhaseId>>;\n readonly onEnter?: ReadonlyBoardPhaseHandlers;\n readonly onExit?: ReadonlyBoardPhaseHandlers;\n};\n\n/**\n * A phase as the board resolved it: deprecated fields are replaced by their new names, so\n * only the new structure leaves `defineBoard()`, and a resolved phase can be declared again.\n */\nexport type BoardPhase<PhaseId extends string> =\n | (ResolvedPhaseBase<PhaseId> & { readonly kind: 'resting' })\n | (ResolvedPhaseBase<PhaseId> & {\n readonly kind: 'working';\n readonly runner: Readonly<BoardPhaseRunner & { agentId: string; context: string }>;\n /** @deprecated Use `runner.context`; kept equal to it. */\n readonly role: string;\n readonly autoStart?: boolean;\n readonly autoStartWhen?: RuleGroup;\n readonly exitTool?: Readonly<{ id: string; autoApprove: boolean; autoApproveWhen?: RuleGroup }>;\n })\n | (ResolvedPhaseBase<PhaseId> & { readonly kind: 'terminal' });\n\ntype ResolvedRunner = Extract<BoardPhase<string>, { kind: 'working' }>['runner'];\ntype ResolvedExitTool = Extract<BoardPhase<string>, { kind: 'working' }>['exitTool'];\n\nexport interface BoardTransition<PhaseId extends string> {\n readonly outcome: string | null;\n readonly to: PhaseId;\n}\n\n/**\n * Terminal phases a card moves to when its tracked source (issue or follow-up) closes.\n * `completed` is used when the source was completed, `canceled` when it was canceled or not planned.\n */\nexport type BoardSourceClosed<PhaseId extends string> = Readonly<{ completed: PhaseId; canceled: PhaseId }>;\n\nexport interface BoardDefinition<BoardId extends string, PhaseId extends string> {\n readonly id: BoardId;\n readonly name: string;\n /** @deprecated Use `name`; kept equal to it for code written against older Factory versions. */\n readonly title: string;\n readonly description?: string;\n readonly initialPhase: PhaseId;\n readonly phases: Readonly<Record<PhaseId, BoardPhase<PhaseId>>>;\n readonly transitions: Readonly<Record<PhaseId, readonly BoardTransition<PhaseId>[]>>;\n readonly rules: ReadonlyFactoryBoardRules;\n /** Tool-result rules keyed by tool name; empty when the board declares none. */\n readonly tools: BoardToolRules;\n /** Integration event handlers for cards on this board; empty when the board declares none. */\n readonly events: BoardEventRules;\n readonly transitionPolicy?: BoardTransitionPolicy;\n /** Where source-closed rules move a card; absent when the board opts out of auto-closing. */\n readonly sourceClosed?: BoardSourceClosed<PhaseId>;\n allowsTransition(from: PhaseId, to: PhaseId): boolean;\n /** Declared kind of a phase, or undefined when the board has no such phase. */\n phaseKind(phase: string): BoardPhaseKind | undefined;\n isWorking(phase: string): boolean;\n isTerminal(phase: string): boolean;\n /** Session context of a working phase; undefined for resting/terminal/unknown phases. */\n roleForPhase(phase: string): string | undefined;\n /** First working phase, in declaration order, running in `role`'s context. */\n phaseForRole(role: string): PhaseId | undefined;\n /**\n * Whether the phase's runs start without anyone approving them, for a card with these facts\n * (`cardRuleFacts`). A phase with a start condition never starts on its own without facts.\n */\n startsAutomatically(phase: string, facts?: RuleFacts): boolean;\n}\n\ntype BoardConfig<BoardId extends string, Phases extends Record<string, BoardPhaseDefinition<keyof Phases & string>>> = {\n id: BoardId;\n name?: string;\n /** @deprecated Use `name`. */\n title?: string;\n description?: string;\n initialPhase: keyof Phases & string;\n phases: Phases;\n tools?: Record<string, BoardToolRule>;\n events?: BoardEventRules;\n transitionPolicy?: BoardTransitionPolicy;\n sourceClosed?: { completed: keyof Phases & string; canceled: keyof Phases & string };\n};\n\nexport class BoardDefinitionError extends Error {\n override name = 'BoardDefinitionError';\n}\n\nconst PHASE_KINDS: ReadonlySet<string> = new Set<BoardPhaseKind>(['resting', 'working', 'terminal']);\n\nfunction validateBoardIdentifier(value: unknown, label: string): void {\n if (!isBoardIdentifier(value)) {\n throw new BoardDefinitionError(`${label} must be a valid board identifier.`);\n }\n}\n\nconst MAX_NAME_LENGTH = 128;\nconst MAX_DESCRIPTION_LENGTH = 2_000;\nconst MAX_INSTRUCTIONS_LENGTH = 1_000;\nconst RUNNER_KEYS: ReadonlySet<string> = new Set(['agentId', 'skill', 'context', 'instructions']);\nconst EXIT_TOOL_KEYS: ReadonlySet<string> = new Set(['id', 'autoApprove', 'autoApproveWhen']);\nconst WORKING_ONLY_FIELDS = ['runner', 'autoStart', 'autoStartWhen', 'exitTool'] as const;\nconst MOVE_TOOL = 'factory_transition_work_item';\n\n/** `name`, falling back to the deprecated `title`; both may be set only to the same text. */\nfunction resolveName(name: unknown, title: unknown, label: string): string {\n if (name !== undefined && title !== undefined && name !== title) {\n throw new BoardDefinitionError(`${label} sets both name and title; drop the deprecated title.`);\n }\n const value = name ?? title;\n if (typeof value !== 'string' || value.trim().length === 0 || value.length > MAX_NAME_LENGTH) {\n throw new BoardDefinitionError(`${label} must declare a name.`);\n }\n return value;\n}\n\nfunction optionalText(value: unknown, label: string, max: number): string | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'string' || value.trim().length === 0 || value.length > max) {\n throw new BoardDefinitionError(`${label} must be non-empty text of at most ${max} characters.`);\n }\n return value;\n}\n\nfunction ruleGroup(value: unknown, label: string): RuleGroup | undefined {\n if (value === undefined) return undefined;\n const parsed = cardRuleGroupSchema.safeParse(value);\n if (!parsed.success) {\n throw new BoardDefinitionError(`${label} is not a valid condition: ${parsed.error.issues[0]?.message}`);\n }\n return parsed.data;\n}\n\nfunction isContext(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0 && value.length <= MAX_ROLE_LENGTH && IDENTIFIER_RE.test(value);\n}\n\nfunction resolveRunner(phaseId: string, phase: BoardPhaseDefinition<string>): ResolvedRunner {\n const runner: unknown = phase.runner ?? {};\n if (!isPlainObject(runner) || Object.keys(runner).some(key => !RUNNER_KEYS.has(key))) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" runner may only set agentId, skill, context and instructions.`);\n }\n const role: unknown = phase.role;\n if (role !== undefined && runner.context !== undefined && role !== runner.context) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" sets both role and runner.context; drop the deprecated role.`);\n }\n const context = runner.context ?? role ?? DEFAULT_PHASE_CONTEXT;\n if (!isContext(context)) throw new BoardDefinitionError(`Working phase \"${phaseId}\" must declare a valid context.`);\n const agentId = runner.agentId ?? FACTORY_AGENT_ID;\n if (agentId !== FACTORY_AGENT_ID) {\n throw new BoardDefinitionError(\n `Phase \"${phaseId}\" names unknown agent \"${String(agentId)}\"; Factory runs \"${FACTORY_AGENT_ID}\".`,\n );\n }\n const skill = runner.skill;\n if (\n skill !== undefined &&\n (typeof skill !== 'string' || skill.length > MAX_SKILL_NAME_LENGTH || !SKILL_NAME_RE.test(skill))\n ) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" runner.skill must be a skill name.`);\n }\n const instructions = optionalText(\n runner.instructions,\n `Phase \"${phaseId}\" runner.instructions`,\n MAX_INSTRUCTIONS_LENGTH,\n );\n return Object.freeze({\n agentId,\n context,\n ...(skill !== undefined ? { skill } : {}),\n ...(instructions !== undefined ? { instructions } : {}),\n });\n}\n\nfunction resolveExitTool(phaseId: string, value: unknown): ResolvedExitTool {\n if (value === undefined) return undefined;\n const declared = typeof value === 'string' ? { id: value } : value;\n if (!isPlainObject(declared) || Object.keys(declared).some(key => !EXIT_TOOL_KEYS.has(key))) {\n throw new BoardDefinitionError(\n `Phase \"${phaseId}\" exitTool must be a tool name or { id, autoApprove, autoApproveWhen }.`,\n );\n }\n const { id, autoApprove = false } = declared;\n if (typeof id !== 'string' || id.length === 0 || id.length > MAX_TOOL_NAME_LENGTH || !IDENTIFIER_RE.test(id)) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" exitTool has an invalid tool name.`);\n }\n if (id === MOVE_TOOL) {\n throw new BoardDefinitionError(\n `Phase \"${phaseId}\" cannot end with ${MOVE_TOOL}: that tool already moves the card.`,\n );\n }\n if (typeof autoApprove !== 'boolean') {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" exitTool.autoApprove must be a boolean.`);\n }\n const autoApproveWhen = ruleGroup(declared.autoApproveWhen, `Phase \"${phaseId}\" exitTool.autoApproveWhen`);\n if (autoApproveWhen && !autoApprove) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" exitTool.autoApproveWhen needs autoApprove.`);\n }\n return Object.freeze({ id, autoApprove, ...(autoApproveWhen ? { autoApproveWhen } : {}) });\n}\n\nfunction validatePhaseSemantics(phaseId: string, phase: BoardPhaseDefinition<string>): void {\n if (!PHASE_KINDS.has(phase.kind as string)) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" must declare kind 'resting', 'working', or 'terminal'.`);\n }\n if (phase.kind === 'working') return;\n if ((phase as { role?: unknown }).role !== undefined) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" is ${phase.kind} and cannot declare a role.`);\n }\n for (const field of WORKING_ONLY_FIELDS) {\n if ((phase as Record<string, unknown>)[field] !== undefined) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" is ${phase.kind} and cannot declare ${field}.`);\n }\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 validateToolRules(tools: unknown): BoardToolRules {\n if (tools === undefined) return Object.freeze({});\n if (!isPlainObject(tools)) throw new BoardDefinitionError('Board tools must be a plain object.');\n const frozen: Record<string, BoardToolRule> = {};\n for (const [toolName, leaf] of Object.entries(tools)) {\n if (toolName.length === 0 || toolName.length > MAX_TOOL_NAME_LENGTH || !IDENTIFIER_RE.test(toolName)) {\n throw new BoardDefinitionError(`Tool rule \"${toolName}\" has an invalid tool name.`);\n }\n if (!isPlainObject(leaf) || Object.keys(leaf).some(key => key !== 'onResult')) {\n throw new BoardDefinitionError(`Tool rule \"${toolName}\" must be an object with only onResult.`);\n }\n if (typeof leaf.onResult !== 'function') {\n throw new BoardDefinitionError(`Tool rule \"${toolName}\" must declare an onResult function.`);\n }\n frozen[toolName] = Object.freeze({ onResult: leaf.onResult as BoardToolResultRuleHandler });\n }\n return Object.freeze(frozen);\n}\n\nfunction validateSourceClosed(\n sourceClosed: unknown,\n phases: Readonly<Record<string, BoardPhaseDefinition<string>>>,\n): BoardSourceClosed<string> | undefined {\n if (sourceClosed === undefined) return undefined;\n if (!isPlainObject(sourceClosed)) throw new BoardDefinitionError('Board sourceClosed must be a plain object.');\n const keys = Object.keys(sourceClosed);\n if (keys.length !== 2 || !keys.includes('completed') || !keys.includes('canceled')) {\n throw new BoardDefinitionError('Board sourceClosed must declare exactly completed and canceled.');\n }\n for (const key of ['completed', 'canceled'] as const) {\n const phase = sourceClosed[key];\n if (typeof phase !== 'string' || !Object.hasOwn(phases, phase) || phases[phase]!.kind !== 'terminal') {\n throw new BoardDefinitionError(`Board sourceClosed.${key} \"${String(phase)}\" must name a terminal phase.`);\n }\n }\n return Object.freeze({ completed: sourceClosed.completed as string, canceled: sourceClosed.canceled as string });\n}\n\nfunction validateEventRules(events: unknown): BoardEventRules {\n if (events === undefined) return Object.freeze({});\n if (!isPlainObject(events)) throw new BoardDefinitionError('Board events must be a plain object.');\n const frozen: Record<string, Readonly<Record<string, unknown>>> = {};\n for (const [integration, handlers] of Object.entries(events)) {\n const known = Object.hasOwn(BOARD_EVENT_NAMES, integration)\n ? BOARD_EVENT_NAMES[integration as BoardEventIntegration]\n : undefined;\n if (!known) throw new BoardDefinitionError(`Board events name unknown integration \"${integration}\".`);\n if (handlers === undefined) continue;\n if (!isPlainObject(handlers)) {\n throw new BoardDefinitionError(`Board events for \"${integration}\" must be a plain object.`);\n }\n const entries: Record<string, unknown> = {};\n for (const [event, handler] of Object.entries(handlers)) {\n if (!known.includes(event)) {\n throw new BoardDefinitionError(`Board events for \"${integration}\" name unknown event \"${event}\".`);\n }\n if (handler === undefined) continue;\n if (handler !== null && typeof handler !== 'function') {\n throw new BoardDefinitionError(`Board event handler \"${integration}.${event}\" must be a function or null.`);\n }\n entries[event] = handler;\n }\n frozen[integration] = Object.freeze(entries);\n }\n return Object.freeze(frozen) as BoardEventRules;\n}\n\n/** The phase's `onEnter` handlers, with its runner's skill for other sources and its instructions on every run. */\nfunction phaseEnterHandlers(\n declared: ReadonlyBoardPhaseHandlers | undefined,\n runner: ResolvedRunner,\n): ReadonlyBoardPhaseHandlers | undefined {\n const handlers: BoardPhaseHandlers = { ...declared };\n if (runner.skill) {\n for (const source of FACTORY_RULE_SOURCES) handlers[source] ??= startSkill(runner.skill, runner.context);\n }\n if (runner.instructions) {\n for (const source of Object.keys(handlers) as FactoryRuleSource[]) {\n handlers[source] = addInstructions(handlers[source]!, runner.instructions);\n }\n }\n return Object.keys(handlers).length > 0 ? handlers : undefined;\n}\n\nconst warnedBoards = new Set<string>();\n\ntype DeclaredBoard = {\n readonly id: string;\n readonly name?: string;\n readonly title?: string;\n readonly phases: Readonly<Record<string, BoardPhaseDefinition<string>>>;\n};\n\n/**\n * Deprecated fields a board declaration still relies on; `defineBoard()` maps each to its\n * replacement. A deprecated field next to its replacement adds nothing, so it is not reported:\n * that is how a resolved board, which carries both, is declared again.\n */\nfunction deprecatedFields(config: DeclaredBoard): string[] {\n const found: string[] = [];\n if (config.title !== undefined && config.name === undefined) found.push('title → name');\n for (const [phaseId, phase] of Object.entries(config.phases)) {\n if (phase.title !== undefined && phase.name === undefined) found.push(`phases.${phaseId}.title → name`);\n if (phase.next !== undefined && !phase.nextPhases?.includes(phase.next)) {\n found.push(`phases.${phaseId}.next → nextPhases`);\n }\n if (phase.role !== undefined && phase.runner?.context === undefined) {\n found.push(`phases.${phaseId}.role → runner.context`);\n }\n }\n return found;\n}\n\nfunction warnDeprecatedFields(config: DeclaredBoard): void {\n if (warnedBoards.has(config.id)) return;\n const found = deprecatedFields(config);\n if (found.length === 0) return;\n warnedBoards.add(config.id);\n console.warn(\n `[Mastra Factory] Board \"${config.id}\" uses deprecated fields: ${found.join(', ')}. ` +\n 'They still work but will be removed in a future release.',\n );\n}\n\n/** Marks a board an app declared with the deprecated `defineBoard()`; a copy does not carry it. */\nconst DEFINED_BOARD = Symbol('DefinedBoard');\n\n/**\n * Declares a board in code.\n *\n * @deprecated Boards are stored per project; manage them with `/web/factory/projects/:id/boards`\n * (README § Stored boards). Code boards are read-only and served alongside each project's stored\n * boards.\n */\nexport function defineBoard<\n const BoardId extends string,\n const Phases extends Record<string, BoardPhaseDefinition<keyof Phases & string>>,\n>(config: BoardConfig<BoardId, Phases>): BoardDefinition<BoardId, keyof Phases & string> {\n return buildBoard(config, true);\n}\n\n/** Whether an app declared the board with the deprecated `defineBoard()`. */\nexport function isDefinedBoard(board: object): boolean {\n return DEFINED_BOARD in board;\n}\n\n/** Validates and resolves a board declaration. Factory's own boards use this directly. */\nexport function compileBoardDefinition<\n const BoardId extends string,\n const Phases extends Record<string, BoardPhaseDefinition<keyof Phases & string>>,\n>(config: BoardConfig<BoardId, Phases>): BoardDefinition<BoardId, keyof Phases & string> {\n return buildBoard(config, false);\n}\n\nfunction buildBoard<\n const BoardId extends string,\n const Phases extends Record<string, BoardPhaseDefinition<keyof Phases & string>>,\n>(config: BoardConfig<BoardId, Phases>, defined: boolean): BoardDefinition<BoardId, keyof Phases & string> {\n type PhaseId = keyof Phases & string;\n validateBoardIdentifier(config.id, 'Board id');\n const boardName = resolveName(config.name, config.title, `Board \"${config.id}\"`);\n const boardDescription = optionalText(config.description, `Board \"${config.id}\" description`, MAX_DESCRIPTION_LENGTH);\n if (config.transitionPolicy !== undefined && typeof config.transitionPolicy !== 'function') {\n throw new BoardDefinitionError('Board transitionPolicy must be a function.');\n }\n const tools = validateToolRules(config.tools);\n const events = validateEventRules(config.events);\n const phaseIds = new Set(Object.keys(config.phases));\n if (phaseIds.size === 0) throw new BoardDefinitionError('A board must define at least one phase.');\n if (!phaseIds.has(config.initialPhase)) {\n throw new BoardDefinitionError(`Initial phase \"${config.initialPhase}\" is not defined.`);\n }\n for (const [phaseId, phase] of Object.entries(config.phases)) {\n validateBoardIdentifier(phaseId, 'Phase id');\n validatePhaseSemantics(phaseId, phase);\n }\n if (config.phases[config.initialPhase]!.kind !== 'resting') {\n throw new BoardDefinitionError(`Initial phase \"${config.initialPhase}\" must be a resting phase.`);\n }\n warnDeprecatedFields(config);\n const sourceClosed = validateSourceClosed(config.sourceClosed, config.phases) as\n | BoardSourceClosed<PhaseId>\n | undefined;\n\n const transitions = Object.fromEntries(\n Object.entries(config.phases).map(([phaseId, phase]) => {\n if (phase.next !== undefined && phase.outcomes) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" cannot define both next and outcomes.`);\n }\n if (phase.nextPhases !== undefined && !Array.isArray(phase.nextPhases)) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" nextPhases must be a list of phases.`);\n }\n const targets: BoardTransition<string>[] =\n phase.next !== undefined\n ? [Object.freeze({ outcome: null, to: phase.next })]\n : Object.entries(phase.outcomes ?? {}).map(([outcome, to]) => Object.freeze({ outcome, to }));\n for (const to of phase.nextPhases ?? []) {\n if (!targets.some(target => target.to === to)) targets.push(Object.freeze({ outcome: null, to }));\n }\n for (const { to } of targets) {\n if (!phaseIds.has(to)) {\n throw new BoardDefinitionError(`Phase \"${phaseId}\" targets undefined phase \"${to}\".`);\n }\n }\n return [phaseId, Object.freeze(targets)];\n }),\n ) as Record<PhaseId, readonly BoardTransition<PhaseId>[]>;\n\n const phases = Object.freeze(\n Object.fromEntries(\n Object.entries(config.phases).map(([phaseId, phase]) => {\n const label = `Phase \"${phaseId}\"`;\n const nextPhases = Object.freeze([\n ...new Set([...(phase.nextPhases ?? []), ...transitions[phaseId as PhaseId]!.map(({ to }) => to)]),\n ]);\n const runner = phase.kind === 'working' ? resolveRunner(phaseId, phase) : undefined;\n const working = phase.kind === 'working' ? phase : undefined;\n if (working?.autoStart !== undefined && typeof working.autoStart !== 'boolean') {\n throw new BoardDefinitionError(`${label} autoStart must be a boolean.`);\n }\n const autoStartWhen = ruleGroup(working?.autoStartWhen, `${label} autoStartWhen`);\n if (autoStartWhen && working?.autoStart !== true) {\n throw new BoardDefinitionError(`${label} autoStartWhen needs autoStart.`);\n }\n const exitTool = resolveExitTool(phaseId, working?.exitTool);\n if (exitTool && nextPhases.length === 0) {\n throw new BoardDefinitionError(`${label} exit tool needs a next phase to move the card to.`);\n }\n const onEnter = runner ? phaseEnterHandlers(phase.onEnter, runner) : phase.onEnter;\n const name = resolveName(phase.name, phase.title, label);\n const description = optionalText(phase.description, `${label} description`, MAX_DESCRIPTION_LENGTH);\n return [\n phaseId,\n Object.freeze({\n name,\n title: name,\n ...(description !== undefined ? { description } : {}),\n kind: phase.kind,\n nextPhases,\n ...(phase.next !== undefined ? { next: phase.next } : {}),\n ...(phase.outcomes ? { outcomes: Object.freeze({ ...phase.outcomes }) } : {}),\n ...(runner ? { runner, role: runner.context } : {}),\n ...(working?.autoStart ? { autoStart: true } : {}),\n ...(autoStartWhen ? { autoStartWhen } : {}),\n ...(exitTool ? { exitTool } : {}),\n ...(onEnter ? { onEnter: Object.freeze({ ...onEnter }) } : {}),\n ...(phase.onExit ? { onExit: Object.freeze({ ...phase.onExit }) } : {}),\n }),\n ];\n }),\n ),\n ) as Readonly<Record<PhaseId, BoardPhase<PhaseId>>>;\n const rules = Object.freeze(\n Object.fromEntries(\n (Object.entries(phases) as [PhaseId, BoardPhase<PhaseId>][]).flatMap(([phaseId, phase]) => {\n const sources = new Set([...Object.keys(phase.onEnter ?? {}), ...Object.keys(phase.onExit ?? {})]);\n if (sources.size === 0) return [];\n return [\n [\n phaseId,\n Object.freeze(\n Object.fromEntries(\n [...sources].map(source => [\n source,\n Object.freeze({\n ...(phase.onEnter?.[source as FactoryRuleSource]\n ? { onEnter: phase.onEnter[source as FactoryRuleSource] }\n : {}),\n ...(phase.onExit?.[source as FactoryRuleSource]\n ? { onExit: phase.onExit[source as FactoryRuleSource] }\n : {}),\n }),\n ]),\n ),\n ),\n ],\n ];\n }),\n ),\n ) as ReadonlyFactoryBoardRules;\n\n const kinds = new Map<string, BoardPhaseKind>();\n const roles = new Map<string, string>();\n const phaseByRole = new Map<string, PhaseId>();\n for (const [phaseId, phase] of Object.entries(phases) as [PhaseId, BoardPhase<PhaseId>][]) {\n kinds.set(phaseId, phase.kind);\n if (phase.kind !== 'working') continue;\n roles.set(phaseId, phase.runner.context);\n if (!phaseByRole.has(phase.runner.context)) phaseByRole.set(phase.runner.context, phaseId);\n }\n\n const board = {\n id: config.id,\n name: boardName,\n title: boardName,\n ...(boardDescription !== undefined ? { description: boardDescription } : {}),\n initialPhase: config.initialPhase,\n phases,\n transitions: Object.freeze(transitions),\n rules: Object.freeze(rules),\n tools,\n events,\n ...(config.transitionPolicy ? { transitionPolicy: config.transitionPolicy } : {}),\n ...(sourceClosed ? { sourceClosed } : {}),\n allowsTransition(from: PhaseId, to: PhaseId) {\n return from === to || transitions[from]?.some(transition => transition.to === to) === true;\n },\n phaseKind: (phase: string) => kinds.get(phase),\n isWorking: (phase: string) => kinds.get(phase) === 'working',\n isTerminal: (phase: string) => kinds.get(phase) === 'terminal',\n roleForPhase: (phase: string) => roles.get(phase),\n phaseForRole: (role: string) => phaseByRole.get(role),\n startsAutomatically: (phase: string, facts?: RuleFacts) => {\n const definition = phases[phase as PhaseId] as BoardPhase<PhaseId> | undefined;\n if (definition?.kind !== 'working' || definition.autoStart !== true) return false;\n if (!definition.autoStartWhen) return true;\n return facts !== undefined && evaluateRuleGroup(definition.autoStartWhen, facts);\n },\n };\n if (defined) Object.defineProperty(board, DEFINED_BOARD, { value: true });\n return Object.freeze(board);\n}\n"],"mappings":"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"}
|