@mastra/factory 0.26.0-alpha.0 → 0.26.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +158 -57
- package/dist/auth.d.ts.map +1 -1
- package/dist/boards/card-facts.d.ts +5 -0
- package/dist/boards/card-facts.d.ts.map +1 -0
- package/dist/boards/card-facts.js +19 -0
- package/dist/boards/card-facts.js.map +1 -0
- package/dist/boards/define-board.d.ts +109 -13
- package/dist/boards/define-board.d.ts.map +1 -1
- package/dist/boards/define-board.js +163 -21
- package/dist/boards/define-board.js.map +1 -1
- package/dist/boards/index.d.ts +4 -3
- package/dist/boards/index.d.ts.map +1 -1
- package/dist/boards/index.js +3 -2
- package/dist/boards/index.js.map +1 -1
- package/dist/boards/legacy-plan-role.d.ts +14 -0
- package/dist/boards/legacy-plan-role.d.ts.map +1 -0
- package/dist/boards/legacy-plan-role.js +32 -0
- package/dist/boards/legacy-plan-role.js.map +1 -0
- package/dist/boards/phase-automation.d.ts +13 -0
- package/dist/boards/phase-automation.d.ts.map +1 -0
- package/dist/boards/phase-automation.js +25 -0
- package/dist/boards/phase-automation.js.map +1 -0
- package/dist/boards/phase-runner.d.ts +13 -0
- package/dist/boards/phase-runner.d.ts.map +1 -0
- package/dist/boards/phase-runner.js +44 -0
- package/dist/boards/phase-runner.js.map +1 -0
- package/dist/boards/relocate.d.ts.map +1 -1
- package/dist/boards/relocate.js +2 -0
- package/dist/boards/relocate.js.map +1 -1
- package/dist/boards/review.d.ts +1 -1
- package/dist/boards/review.d.ts.map +1 -1
- package/dist/boards/review.js +18 -18
- package/dist/boards/review.js.map +1 -1
- package/dist/boards/semantics.d.ts.map +1 -1
- package/dist/boards/semantics.js +11 -7
- package/dist/boards/semantics.js.map +1 -1
- package/dist/boards/transition-policy.d.ts +10 -10
- package/dist/boards/work-tool-rules.d.ts +3 -3
- package/dist/boards/work-tool-rules.d.ts.map +1 -1
- package/dist/boards/work-tool-rules.js +1 -1
- package/dist/boards/work-tool-rules.js.map +1 -1
- package/dist/boards/work.d.ts +3 -3
- package/dist/boards/work.d.ts.map +1 -1
- package/dist/boards/work.js +31 -29
- package/dist/boards/work.js.map +1 -1
- package/dist/environment/build-runner.d.ts +4 -4
- package/dist/environment/build-runner.d.ts.map +1 -1
- package/dist/environment/build-workflow.d.ts +6 -6
- package/dist/environment/build-workflow.js +1 -1
- package/dist/environment/build.d.ts +2 -2
- 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 +8 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +8 -2
- package/dist/factory.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/integrations/github/app-identity.d.ts.map +1 -1
- package/dist/integrations/github/default-rules.d.ts +71 -71
- package/dist/integrations/github/default-rules.d.ts.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/reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/github/rules.d.ts.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/gitlab/api.d.ts.map +1 -1
- package/dist/integrations/gitlab/default-rules.d.ts +38 -38
- package/dist/integrations/gitlab/default-rules.d.ts.map +1 -1
- package/dist/integrations/gitlab/integration.d.ts.map +1 -1
- package/dist/integrations/gitlab/rules.d.ts.map +1 -1
- package/dist/integrations/incidentio/api.d.ts.map +1 -1
- package/dist/integrations/incidentio/default-rules.d.ts +3 -3
- package/dist/integrations/incidentio/default-rules.d.ts.map +1 -1
- package/dist/integrations/incidentio/integration.d.ts.map +1 -1
- package/dist/integrations/incidentio/rules.d.ts.map +1 -1
- package/dist/integrations/issue-reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/jira/api.d.ts +1 -1
- package/dist/integrations/jira/api.d.ts.map +1 -1
- package/dist/integrations/jira/default-rules.d.ts +3 -3
- package/dist/integrations/jira/default-rules.d.ts.map +1 -1
- package/dist/integrations/jira/integration.d.ts.map +1 -1
- package/dist/integrations/jira/rules.d.ts.map +1 -1
- package/dist/integrations/linear/default-rules.d.ts +8 -8
- package/dist/integrations/linear/default-rules.d.ts.map +1 -1
- package/dist/integrations/linear/integration.d.ts.map +1 -1
- package/dist/integrations/linear/rules.d.ts.map +1 -1
- package/dist/integrations/platform/api-client.d.ts.map +1 -1
- package/dist/integrations/platform/github/event-worker.d.ts.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/gitlab/event-worker.d.ts.map +1 -1
- package/dist/integrations/platform/gitlab/integration.d.ts.map +1 -1
- package/dist/integrations/platform/incidentio/integration.d.ts.map +1 -1
- package/dist/integrations/platform/jira/integration.d.ts.map +1 -1
- package/dist/integrations/platform/linear/event-worker.d.ts.map +1 -1
- package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
- package/dist/integrations/slack/channel-reply-processor.d.ts.map +1 -1
- package/dist/integrations/slack/channel-session-link-processor.d.ts.map +1 -1
- package/dist/integrations/slack/feed-publisher.d.ts.map +1 -1
- package/dist/integrations/slack/integration.d.ts.map +1 -1
- package/dist/integrations/slack/reply-reminder-processor.d.ts.map +1 -1
- package/dist/integrations/slack/reply-tool.d.ts.map +1 -1
- package/dist/integrations/slack/slack.d.ts.map +1 -1
- package/dist/integrations/workos/integration.d.ts.map +1 -1
- package/dist/mcp/events.d.ts +3 -3
- package/dist/mcp/routes.js +1 -1
- package/dist/routes/attention-activity.d.ts +1 -1
- package/dist/routes/attention-activity.d.ts.map +1 -1
- package/dist/routes/attention-parked.d.ts +1 -1
- package/dist/routes/attention-parked.d.ts.map +1 -1
- package/dist/routes/attention-providers.d.ts +1 -1
- package/dist/routes/attention-providers.d.ts.map +1 -1
- package/dist/routes/automation-runs.d.ts.map +1 -1
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/contracts.d.ts +159 -136
- package/dist/routes/contracts.d.ts.map +1 -1
- package/dist/routes/contracts.js +23 -0
- package/dist/routes/contracts.js.map +1 -1
- package/dist/routes/fs.d.ts.map +1 -1
- package/dist/routes/fs.js +24 -0
- package/dist/routes/fs.js.map +1 -1
- package/dist/routes/intake.d.ts.map +1 -1
- package/dist/routes/knowledge.d.ts.map +1 -1
- package/dist/routes/oauth.d.ts.map +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/route.d.ts.map +1 -1
- package/dist/routes/skills.d.ts +3 -0
- package/dist/routes/skills.d.ts.map +1 -1
- package/dist/routes/skills.js +1 -1
- package/dist/routes/skills.js.map +1 -1
- package/dist/routes/surface.d.ts +3 -0
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +24 -22
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/telemetry.d.ts.map +1 -1
- package/dist/routes/tenant-credentials.d.ts.map +1 -1
- package/dist/routes/work-items.d.ts.map +1 -1
- package/dist/routes/work-items.js +19 -3
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/decision-applicability.d.ts.map +1 -1
- package/dist/rules/decision-applicability.js +3 -1
- package/dist/rules/decision-applicability.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.map +1 -1
- package/dist/rules/dispatcher.js +17 -3
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/processor.d.ts.map +1 -1
- package/dist/rules/processor.js +4 -2
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/rule-group.d.ts +29 -0
- package/dist/rules/rule-group.d.ts.map +1 -0
- package/dist/rules/rule-group.js +141 -0
- package/dist/rules/rule-group.js.map +1 -0
- package/dist/rules/start-coordinator.d.ts.map +1 -1
- package/dist/rules/terminal-cleanup.d.ts.map +1 -1
- package/dist/rules/tools.d.ts +1 -1
- package/dist/rules/tools.d.ts.map +1 -1
- package/dist/rules/transition-service.d.ts.map +1 -1
- package/dist/rules/transition-service.js +5 -3
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.d.ts +25 -14
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/types.js.map +1 -1
- package/dist/rules/validation.d.ts +2 -0
- package/dist/rules/validation.d.ts.map +1 -1
- package/dist/rules/validation.js +6 -3
- package/dist/rules/validation.js.map +1 -1
- package/dist/sandbox/callback-factory-sandbox.d.ts.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/sandbox/session-retirement.d.ts.map +1 -1
- package/dist/session/environment-state-processor.d.ts.map +1 -1
- package/dist/session/factory-session.d.ts.map +1 -1
- package/dist/session/live-sessions.d.ts.map +1 -1
- package/dist/session/reply-credential-processor.d.ts.map +1 -1
- package/dist/session/run-audit.d.ts +1 -1
- package/dist/session/run-audit.d.ts.map +1 -1
- package/dist/skills/app-skills.d.ts +11 -0
- package/dist/skills/app-skills.d.ts.map +1 -0
- package/dist/skills/app-skills.js +37 -0
- package/dist/skills/app-skills.js.map +1 -0
- package/dist/skills/catalog.d.ts +9 -3
- package/dist/skills/catalog.d.ts.map +1 -1
- package/dist/skills/catalog.js +35 -19
- package/dist/skills/catalog.js.map +1 -1
- package/dist/skills/service.d.ts.map +1 -1
- package/dist/spa-static.d.ts.map +1 -1
- package/dist/storage/domains/audit/actions.d.ts +6 -6
- package/dist/storage/domains/audit/actions.d.ts.map +1 -1
- package/dist/storage/domains/audit/actors.d.ts +1 -1
- package/dist/storage/domains/audit/actors.d.ts.map +1 -1
- package/dist/storage/domains/audit/base.d.ts.map +1 -1
- package/dist/storage/domains/audit/domain.d.ts.map +1 -1
- package/dist/storage/domains/channel-identity/base.d.ts.map +1 -1
- package/dist/storage/domains/comments/base.d.ts.map +1 -1
- package/dist/storage/domains/comments/domain.d.ts.map +1 -1
- package/dist/storage/domains/comments/feed-context.d.ts.map +1 -1
- package/dist/storage/domains/credentials/base.d.ts.map +1 -1
- package/dist/storage/domains/custom-providers/base.d.ts.map +1 -1
- package/dist/storage/domains/filesystem/base.d.ts.map +1 -1
- package/dist/storage/domains/intake/base.d.ts.map +1 -1
- package/dist/storage/domains/integrations/base.d.ts.map +1 -1
- package/dist/storage/domains/memory-settings/base.d.ts.map +1 -1
- package/dist/storage/domains/model-defaults/base.d.ts.map +1 -1
- package/dist/storage/domains/projects/base.d.ts +1 -1
- package/dist/storage/domains/projects/base.d.ts.map +1 -1
- package/dist/storage/domains/queue-health/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/inmemory.d.ts +5 -5
- package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +2 -2
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +1 -0
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/storage/domains/work-items/board-version.d.ts.map +1 -1
- package/dist/telemetry-types.d.ts +1 -1
- package/dist/telemetry-types.d.ts.map +1 -1
- package/dist/timing.d.ts.map +1 -1
- package/dist/tools/session-tools.d.ts.map +1 -1
- package/dist/tools/session-tools.js +3 -1
- package/dist/tools/session-tools.js.map +1 -1
- package/dist/tools/sessions-state-processor.d.ts.map +1 -1
- package/dist/tools/work-item-tools.js +1 -1
- package/dist/workspace.d.ts +15 -6
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +79 -18
- package/dist/workspace.js.map +1 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -66,12 +66,12 @@ import { defineBoard } from '@mastra/factory/boards';
|
|
|
66
66
|
|
|
67
67
|
const releaseBoard = defineBoard({
|
|
68
68
|
id: 'release',
|
|
69
|
-
|
|
70
|
-
initialPhase: '
|
|
69
|
+
name: 'Release',
|
|
70
|
+
initialPhase: 'backlog',
|
|
71
71
|
phases: {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
backlog: { name: 'Backlog', kind: 'resting', nextPhases: ['done'] },
|
|
73
|
+
done: {
|
|
74
|
+
name: 'Done',
|
|
75
75
|
kind: 'terminal',
|
|
76
76
|
onEnter: {
|
|
77
77
|
manual: () => ({ type: 'reject', code: 'release_held', reason: 'Release is held.' }),
|
|
@@ -126,13 +126,13 @@ When a tracked GitHub, GitLab, Linear, or Jira issue or incident.io follow-up is
|
|
|
126
126
|
```typescript
|
|
127
127
|
const releaseBoard = defineBoard({
|
|
128
128
|
id: 'release',
|
|
129
|
-
|
|
130
|
-
initialPhase: '
|
|
131
|
-
sourceClosed: { completed: '
|
|
129
|
+
name: 'Release',
|
|
130
|
+
initialPhase: 'backlog',
|
|
131
|
+
sourceClosed: { completed: 'done', canceled: 'dropped' },
|
|
132
132
|
phases: {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
dropped: {
|
|
133
|
+
backlog: { name: 'Backlog', kind: 'resting', nextPhases: ['done', 'dropped'] },
|
|
134
|
+
done: { name: 'Done', kind: 'terminal' },
|
|
135
|
+
dropped: { name: 'Dropped', kind: 'terminal' },
|
|
136
136
|
},
|
|
137
137
|
});
|
|
138
138
|
```
|
|
@@ -148,17 +148,17 @@ import { defineBoard } from '@mastra/factory/boards';
|
|
|
148
148
|
import type { BoardToolResultRuleHandler } from '@mastra/factory/boards';
|
|
149
149
|
|
|
150
150
|
const shipIt: BoardToolResultRuleHandler = context => {
|
|
151
|
-
if (context.result.status !== 'success' || context.item.stages[0] !== '
|
|
151
|
+
if (context.result.status !== 'success' || context.item.stages[0] !== 'backlog') return;
|
|
152
152
|
return { type: 'notify', idempotencyKey: `${context.ingress.id}:shipped`, title: 'Release shipped' };
|
|
153
153
|
};
|
|
154
154
|
|
|
155
155
|
const releaseBoard = defineBoard({
|
|
156
156
|
id: 'release',
|
|
157
|
-
|
|
158
|
-
initialPhase: '
|
|
157
|
+
name: 'Release',
|
|
158
|
+
initialPhase: 'backlog',
|
|
159
159
|
phases: {
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
backlog: { name: 'Backlog', kind: 'resting', nextPhases: ['done'] },
|
|
161
|
+
done: { name: 'Done', kind: 'terminal' },
|
|
162
162
|
},
|
|
163
163
|
tools: { ship_it: { onResult: shipIt } },
|
|
164
164
|
});
|
|
@@ -166,7 +166,7 @@ const releaseBoard = defineBoard({
|
|
|
166
166
|
|
|
167
167
|
The handler receives the bound item, actor, board, tool name, normalized result, and `configVersion`, and returns one decision or `undefined`. Tool names follow the identifier rules for decision roles; `onResult` must be a function and the leaf may contain nothing else. Violations are `BoardDefinitionError`s at definition time.
|
|
168
168
|
|
|
169
|
-
The default Work board declares
|
|
169
|
+
The default Work board declares two rules. `submit_plan`: in an interactive session, a successful result whose content starts with `Plan approved.` transitions a Planning card to Execute when the actor is the planning agent (`work`, or `plan` for cards planned before Planning moved to `work`). `factory_record_review_verdict` tells the builder to open the change request once self-review approves. Review declares none. Rules resolve from the installed board, so a replacement `work` board can declare its own `tools.submit_plan.onResult`. Resolution is fail-closed: a tool result on a card whose board is not installed, or whose board does not declare that tool, fires no rule. Other boards inherit nothing from Work even if they reuse its phase names.
|
|
170
170
|
|
|
171
171
|
### Board event rules
|
|
172
172
|
|
|
@@ -177,7 +177,7 @@ import { defineBoard } from '@mastra/factory';
|
|
|
177
177
|
|
|
178
178
|
const deliveryBoard = defineBoard({
|
|
179
179
|
id: 'delivery',
|
|
180
|
-
|
|
180
|
+
name: 'Delivery',
|
|
181
181
|
initialPhase: 'triage',
|
|
182
182
|
phases: {/* ... */},
|
|
183
183
|
events: {
|
|
@@ -192,7 +192,7 @@ const deliveryBoard = defineBoard({
|
|
|
192
192
|
},
|
|
193
193
|
linear: {
|
|
194
194
|
issueClosed: context =>
|
|
195
|
-
context.issue.stateType === 'canceled' && context.phase?.
|
|
195
|
+
context.issue.stateType === 'canceled' && context.phase?.nextPhases.includes('canceled')
|
|
196
196
|
? {
|
|
197
197
|
type: 'transition',
|
|
198
198
|
idempotencyKey: `${context.ingress.id}:canceled`,
|
|
@@ -215,7 +215,7 @@ For each event, Factory picks the handler in this order:
|
|
|
215
215
|
|
|
216
216
|
A board handler that returns a decision replaces the default for that card. One that returns nothing lets the default run, so card-independent defaults such as dismissing stale Factory reviews still apply. The stock Work and Review behavior stays in the integration defaults and never acts on cards on other boards, so a custom board needs no board guards and no delegation to stock handlers.
|
|
217
217
|
|
|
218
|
-
Every integration rule context bound to a card carries `phase`: `{ id, kind,
|
|
218
|
+
Every integration rule context bound to a card carries `phase`: `{ id, kind, context?, nextPhases, outcomes }`, describing what the card's current phase means on its board. `context` is the session context of a working phase (`role` carries the same value and is deprecated), `nextPhases` lists the phases the card may move to, and `outcomes` lists the outcome names the phase declares, if any. `phase` is absent when the card sits in more than one stage or its board does not declare the phase.
|
|
219
219
|
|
|
220
220
|
Unknown integrations, unknown event names, and handler values other than a function or `null` are rejected by `defineBoard` with a `BoardDefinitionError`.
|
|
221
221
|
|
|
@@ -236,7 +236,7 @@ new MastraFactory({ storage, rules: defaultFactoryRules({ version: 'v2', overrid
|
|
|
236
236
|
new MastraFactory({ storage, configVersion: 'v2', boards: [defineBoard({ ..., tools: { my_tool: { onResult } } })] });
|
|
237
237
|
```
|
|
238
238
|
|
|
239
|
-
Contexts that carried `ruleSetVersion` now carry `configVersion`. To
|
|
239
|
+
Contexts that carried `ruleSetVersion` now carry `configVersion`. To add a tool-result rule to Work, declare it under `tools` on the installed replacement `work` board.
|
|
240
240
|
|
|
241
241
|
### Board transition policy
|
|
242
242
|
|
|
@@ -249,19 +249,19 @@ import { defineBoard } from '@mastra/factory/boards';
|
|
|
249
249
|
import type { BoardTransitionPolicy } from '@mastra/factory/boards';
|
|
250
250
|
|
|
251
251
|
const releasePolicy: BoardTransitionPolicy = context => {
|
|
252
|
-
if (context.toStage === '
|
|
252
|
+
if (context.toStage === 'build' && !context.isHumanTransition) {
|
|
253
253
|
return { type: 'reject', code: 'approval_required', reason: 'A person must approve this release.' };
|
|
254
254
|
}
|
|
255
255
|
};
|
|
256
256
|
|
|
257
257
|
const releaseBoard = defineBoard({
|
|
258
258
|
id: 'release',
|
|
259
|
-
|
|
259
|
+
name: 'Release',
|
|
260
260
|
initialPhase: 'approval',
|
|
261
261
|
transitionPolicy: releasePolicy,
|
|
262
262
|
phases: {
|
|
263
|
-
approval: {
|
|
264
|
-
|
|
263
|
+
approval: { name: 'Approval', kind: 'resting', nextPhases: ['build'] },
|
|
264
|
+
build: { name: 'Build', kind: 'working', runner: { context: 'release' } },
|
|
265
265
|
},
|
|
266
266
|
});
|
|
267
267
|
// Install through new MastraFactory({ storage, boards: [releaseBoard] }).
|
|
@@ -280,47 +280,148 @@ A policy cannot bypass topology, ingress authorization, board ownership, externa
|
|
|
280
280
|
Every phase declares what it _is_ with a required `kind`; `defineBoard()` rejects a phase without one.
|
|
281
281
|
|
|
282
282
|
- `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
|
-
- `working` — an agent
|
|
284
|
-
- `terminal` — the card is finished. Entering it releases the sandbox and lets sweeps supersede stale decisions and revoke run bindings. `
|
|
283
|
+
- `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.
|
|
284
|
+
- `terminal` — the card is finished. Entering it releases the sandbox and lets sweeps supersede stale decisions and revoke run bindings. `runner` is not allowed.
|
|
285
285
|
|
|
286
286
|
```typescript
|
|
287
287
|
const releaseBoard = defineBoard({
|
|
288
288
|
id: 'release',
|
|
289
|
-
|
|
290
|
-
initialPhase: '
|
|
289
|
+
name: 'Release',
|
|
290
|
+
initialPhase: 'backlog',
|
|
291
291
|
phases: {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
292
|
+
backlog: { name: 'Backlog', kind: 'resting', nextPhases: ['build'] },
|
|
293
|
+
build: { name: 'Build', kind: 'working', runner: { context: 'release' }, nextPhases: ['done'] },
|
|
294
|
+
done: { name: 'Done', kind: 'terminal' },
|
|
295
295
|
},
|
|
296
296
|
});
|
|
297
297
|
```
|
|
298
298
|
|
|
299
|
-
Work declares `intake` resting; `triage`, `planning`, `execute`, and `review` working with
|
|
299
|
+
Work declares `intake` resting; `triage`, `planning`, `execute`, and `review` working with contexts `triage`, `work`, `work`, and `work`; `done` and `canceled` terminal. Review declares `intake` resting, `review` working with context `review`, and `done`/`canceled` terminal. The definition exposes the derived helpers `phaseKind`, `isWorking`, `isTerminal`, `roleForPhase`, and `phaseForRole`.
|
|
300
|
+
|
|
301
|
+
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.
|
|
300
302
|
|
|
301
303
|
Consent, the external-author guard, kickoff seating, run-start lanes, terminal cleanup, and the closed-PR and issue sweeps all read the installed board's declarations; 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.
|
|
302
304
|
|
|
303
305
|
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.
|
|
304
306
|
|
|
305
|
-
**Migration:** Existing `defineBoard()` calls must add `kind` to every phase
|
|
307
|
+
**Migration:** Existing `defineBoard()` calls must add `kind` to every phase. Working phases name their session context with `runner.context`.
|
|
306
308
|
|
|
307
309
|
```typescript
|
|
308
310
|
// before
|
|
309
|
-
phases: {
|
|
311
|
+
phases: { backlog: { title: 'Backlog', next: 'done' }, done: { title: 'Done' } }
|
|
310
312
|
// after
|
|
311
313
|
phases: {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
+
backlog: { name: 'Backlog', kind: 'resting', nextPhases: ['done'] },
|
|
315
|
+
done: { name: 'Done', kind: 'terminal' },
|
|
314
316
|
}
|
|
315
317
|
```
|
|
316
318
|
|
|
317
319
|
**Remaining limitations:** Throughput and lead-time metrics still count completions by Work's `done` phase. `factory-ui` still renders the built-in stage and role pipeline.
|
|
318
320
|
|
|
321
|
+
### Phase runners, automatic starts and exit tools
|
|
322
|
+
|
|
323
|
+
Boards and phases take `name` and an optional `description`. A phase lists the phases a card may move to in `nextPhases`. A working phase can also declare:
|
|
324
|
+
|
|
325
|
+
- `runner` — `{ agentId?, skill?, context?, instructions? }`. `context` names the session the phase runs in (defaults to `work`); phases that share a context share a session. When the agent moves its own card into another phase of its context, that phase's `skill` still starts: its prompt is queued onto the agent's run. `skill` starts that skill when a card enters the phase from a source the phase has no `onEnter` handler for. It names a built-in Factory skill or one of your app's skills (see [Skills for custom boards](#skills-for-custom-boards)). `instructions` (up to 1,000 characters) are added to every run the phase starts. `agentId` defaults to `code-agent`, the only agent Factory runs today.
|
|
326
|
+
- `autoStart` and `autoStartWhen` — the phase's runs start without a person's approval, for every card or only for cards matching the rule. Cards from outside the write-access circle still wait for a person.
|
|
327
|
+
- `exitTool` — a tool name, or `{ id, autoApprove, autoApproveWhen }`, that ends the phase. The factory-phase signal tells the agent the phase ends when that tool succeeds and lists `nextPhases`; the agent then moves the card itself with `factory_transition_work_item`, so it picks where the card goes. The phase needs at least one next phase. `autoApprove` answers the person's approval the tool waits for, for every card or only cards matching `autoApproveWhen`. Factory sessions already run tools without asking, so today this matters for `submit_plan`: an auto-approved plan is accepted without a person. `defineBoard()` accepts `autoApprove` on any exit tool, and the catalog reports it, but on other tools it has no effect yet.
|
|
328
|
+
|
|
329
|
+
Rules test a card's facts: `item.labels`, `item.title`, `item.author`, `source.kind` and `source.integration`.
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
const LOW_EFFORT = {
|
|
333
|
+
operator: 'AND',
|
|
334
|
+
conditions: [{ field: 'item.labels', operator: 'contains', value: 'effort:low' }],
|
|
335
|
+
} as const;
|
|
336
|
+
|
|
337
|
+
const releaseBoard = defineBoard({
|
|
338
|
+
id: 'release',
|
|
339
|
+
name: 'Release',
|
|
340
|
+
initialPhase: 'backlog',
|
|
341
|
+
phases: {
|
|
342
|
+
backlog: { name: 'Backlog', kind: 'resting', nextPhases: ['plan'] },
|
|
343
|
+
plan: {
|
|
344
|
+
name: 'Plan',
|
|
345
|
+
kind: 'working',
|
|
346
|
+
runner: { context: 'build', skill: 'factory-plan' },
|
|
347
|
+
autoStart: true,
|
|
348
|
+
autoStartWhen: LOW_EFFORT,
|
|
349
|
+
exitTool: { id: 'submit_plan', autoApprove: true },
|
|
350
|
+
nextPhases: ['build', 'canceled'],
|
|
351
|
+
},
|
|
352
|
+
build: { name: 'Build', kind: 'working', runner: { context: 'build' }, nextPhases: ['done'] },
|
|
353
|
+
done: { name: 'Done', kind: 'terminal' },
|
|
354
|
+
canceled: { name: 'Canceled', kind: 'terminal' },
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
```
|
|
358
|
+
|
|
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, and the one `new MastraFactory({ boards })` takes, has only the new fields, so code that reads `board.title`, `phase.title`, `phase.role` or `phase.next` must switch to `name`, `runner.context` and `nextPhases`. 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
|
+
|
|
361
|
+
### Skills for custom boards
|
|
362
|
+
|
|
363
|
+
A phase's `runner.skill` runs a skill when a card enters the phase. Use a built-in skill such as `factory-plan`, or write your own. Factory finds a skill in this order; the first match wins:
|
|
364
|
+
|
|
365
|
+
1. **Code skills** — passed to `new MastraFactory({ skills })`, created with `createSkill()` from `@mastra/core/skills`.
|
|
366
|
+
2. **Folder skills** — `src/mastra/factory-skills/<name>/SKILL.md` in your app. `mastra build` copies the folder into the build output. The older `src/mastra/public/factory-skills` still works; when both exist, `src/mastra/factory-skills` wins. Factory also looks in `public/factory-skills`, `factory-skills` and `output/factory-skills` under the working directory, and uses the first that exists. Supporting files, such as `references/`, can sit next to `SKILL.md`.
|
|
367
|
+
3. **Built-in skills** shipped with `@mastra/factory`.
|
|
368
|
+
|
|
369
|
+
A skill with the same name as a built-in skill replaces it, for the built-in boards too. A code skill replaces the whole folder skill of the same name, including its supporting files. Repository skills in a project's own repository never replace these.
|
|
370
|
+
|
|
371
|
+
Skill names use 1–64 lowercase letters, digits and single hyphens, such as `release-notes`. A folder skill's `name` must match its directory name. Names in `skills` must be unique, or the constructor throws.
|
|
372
|
+
|
|
373
|
+
```typescript
|
|
374
|
+
import { createSkill } from '@mastra/core/skills';
|
|
375
|
+
import { MastraFactory } from '@mastra/factory';
|
|
376
|
+
import { defineBoard } from '@mastra/factory/boards';
|
|
377
|
+
|
|
378
|
+
const releaseNotes = createSkill({
|
|
379
|
+
name: 'release-notes',
|
|
380
|
+
description: 'Draft release notes for a work item',
|
|
381
|
+
instructions: 'Group the release notes by package and end with a one-line summary. Then move the card to Published.',
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
const notesBoard = defineBoard({
|
|
385
|
+
id: 'notes',
|
|
386
|
+
name: 'Notes',
|
|
387
|
+
initialPhase: 'backlog',
|
|
388
|
+
phases: {
|
|
389
|
+
backlog: { name: 'Backlog', kind: 'resting', nextPhases: ['drafting'] },
|
|
390
|
+
drafting: {
|
|
391
|
+
name: 'Drafting',
|
|
392
|
+
kind: 'working',
|
|
393
|
+
runner: { context: 'writer', skill: 'release-notes' },
|
|
394
|
+
nextPhases: ['published'],
|
|
395
|
+
},
|
|
396
|
+
published: { name: 'Published', kind: 'terminal' },
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
const factory = new MastraFactory({ ...config, boards: [notesBoard], skills: [releaseNotes] });
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
The same skill as a folder skill is `src/mastra/factory-skills/release-notes/SKILL.md`:
|
|
404
|
+
|
|
405
|
+
```markdown
|
|
406
|
+
---
|
|
407
|
+
name: release-notes
|
|
408
|
+
description: Draft release notes for a work item
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
Group the release notes by package and end with a one-line summary. Then move the card to Published.
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
The skill receives the card's link, or its title when it has none, as arguments. Every Factory session can also load your skills on request, like the built-in ones.
|
|
415
|
+
|
|
416
|
+
When a card enters the phase and the skill does not exist, no run starts and the card stays in the phase. The start fails with `Skill not found: <name>.`; after a few quick retries it stays failed, and you can retry it once the skill exists. The constructor logs a warning for each phase that names a missing skill. It also warns when a phase outside the `review` context runs a review skill (`factory-review`, `factory-rereview`, `factory-self-review`, `factory-gitlab-review`, `factory-gitlab-rereview`), because sessions only load those for reviews.
|
|
417
|
+
|
|
418
|
+
Settings › Skills shows the skill each custom phase runs, marks a phase whose skill is missing, marks built-in skills your app replaces, and lists your other skills under **App skills**.
|
|
419
|
+
|
|
319
420
|
### Execute a custom board
|
|
320
421
|
|
|
321
422
|
Installed 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.
|
|
322
423
|
|
|
323
|
-
This configuration runs a release rehearsal through `
|
|
424
|
+
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.
|
|
324
425
|
|
|
325
426
|
```typescript
|
|
326
427
|
import { MastraFactory } from '@mastra/factory';
|
|
@@ -328,14 +429,14 @@ import type { MastraFactoryConfig } from '@mastra/factory';
|
|
|
328
429
|
import { defineBoard } from '@mastra/factory/boards';
|
|
329
430
|
import type { BoardPhaseDefinition } from '@mastra/factory/boards';
|
|
330
431
|
|
|
331
|
-
type ReleasePhase = '
|
|
432
|
+
type ReleasePhase = 'backlog' | 'preparing' | 'build' | 'done';
|
|
332
433
|
|
|
333
434
|
const releaseBoard = defineBoard<'release', Record<ReleasePhase, BoardPhaseDefinition<ReleasePhase>>>({
|
|
334
435
|
id: 'release',
|
|
335
|
-
|
|
336
|
-
initialPhase: '
|
|
436
|
+
name: 'Release',
|
|
437
|
+
initialPhase: 'backlog',
|
|
337
438
|
transitionPolicy: context => {
|
|
338
|
-
if (context.fromStage === '
|
|
439
|
+
if (context.fromStage === 'backlog' && context.toStage === 'preparing' && !context.isHumanTransition) {
|
|
339
440
|
return {
|
|
340
441
|
type: 'reject',
|
|
341
442
|
code: 'approval_required',
|
|
@@ -344,27 +445,27 @@ const releaseBoard = defineBoard<'release', Record<ReleasePhase, BoardPhaseDefin
|
|
|
344
445
|
}
|
|
345
446
|
},
|
|
346
447
|
phases: {
|
|
347
|
-
|
|
448
|
+
backlog: { name: 'Backlog', kind: 'resting', nextPhases: ['preparing'] },
|
|
348
449
|
preparing: {
|
|
349
|
-
|
|
450
|
+
name: 'Preparing',
|
|
350
451
|
kind: 'working',
|
|
351
|
-
|
|
352
|
-
|
|
452
|
+
runner: { context: 'release-preparer' },
|
|
453
|
+
nextPhases: ['build'],
|
|
353
454
|
onEnter: {
|
|
354
455
|
issue: context => ({
|
|
355
456
|
type: 'invokeSkill',
|
|
356
457
|
idempotencyKey: `${context.ingress.id}:prepare`,
|
|
357
458
|
role: 'release-preparer',
|
|
358
459
|
prompt:
|
|
359
|
-
'Inspect the release changes. When ready, call factory_transition_work_item with stage
|
|
460
|
+
'Inspect the release changes. When ready, call factory_transition_work_item with stage build and the current expectedRevision from the Factory phase signal.',
|
|
360
461
|
}),
|
|
361
462
|
},
|
|
362
463
|
},
|
|
363
|
-
|
|
364
|
-
|
|
464
|
+
build: {
|
|
465
|
+
name: 'Build',
|
|
365
466
|
kind: 'working',
|
|
366
|
-
|
|
367
|
-
|
|
467
|
+
runner: { context: 'release-publisher' },
|
|
468
|
+
nextPhases: ['done'],
|
|
368
469
|
onEnter: {
|
|
369
470
|
issue: context => ({
|
|
370
471
|
type: 'invokeSkill',
|
|
@@ -375,13 +476,13 @@ const releaseBoard = defineBoard<'release', Record<ReleasePhase, BoardPhaseDefin
|
|
|
375
476
|
}),
|
|
376
477
|
},
|
|
377
478
|
},
|
|
378
|
-
|
|
479
|
+
done: { name: 'Done', kind: 'terminal' },
|
|
379
480
|
},
|
|
380
481
|
tools: {
|
|
381
482
|
execute_command: {
|
|
382
483
|
onResult: context => {
|
|
383
484
|
if (
|
|
384
|
-
context.item.stages[0] !== '
|
|
485
|
+
context.item.stages[0] !== 'build' ||
|
|
385
486
|
context.result.status !== 'success' ||
|
|
386
487
|
typeof context.result.value !== 'string' ||
|
|
387
488
|
!context.result.value.trimEnd().endsWith('RELEASE_CHECK_PASSED')
|
|
@@ -392,7 +493,7 @@ const releaseBoard = defineBoard<'release', Record<ReleasePhase, BoardPhaseDefin
|
|
|
392
493
|
type: 'transition',
|
|
393
494
|
idempotencyKey: `${context.ingress.id}:checked`,
|
|
394
495
|
board: 'release',
|
|
395
|
-
stage: '
|
|
496
|
+
stage: 'done',
|
|
396
497
|
};
|
|
397
498
|
},
|
|
398
499
|
},
|
|
@@ -406,7 +507,7 @@ export function createFactory(config: Omit<MastraFactoryConfig, 'boards' | 'incl
|
|
|
406
507
|
|
|
407
508
|
Use the host's normal `prepare()`, `new Mastra(...)`, and `finalize()` sequence. Change the hardcoded `includeDefaultBoards: true` in `createFactory` to `false` to run without Work or Review. Working roles name bindings on the shared Code Agent; they do not register separate agents. Factory has no per-role agent configuration option. The board's kickoff prompts supply the role-specific instructions.
|
|
408
509
|
|
|
409
|
-
Create a card with `POST /web/factory/projects/:id/work-items`, passing `board: 'release'`, a title, and the GitHub issue's `externalSource`. The card starts in `
|
|
510
|
+
Create a card with `POST /web/factory/projects/:id/work-items`, passing `board: 'release'`, a title, and the GitHub issue's `externalSource`. The card starts in `backlog`. Then use `POST /web/factory/projects/:id/work-items/:workItemId/transition` with `board: 'release'`, `stage: 'preparing'`, the returned `expectedRevision`, a unique `requestId`, and a `cause`. Send these requests as an authorized user using the host's authentication. The human transition satisfies this board's policy and starts the preparer. Its bound tool advances to `build`; the publisher's completed check produces a deferred transition to `done`. Terminal entry revokes the binding and releases the sandbox. The Factory UI performs the same operations against installed boards (see below); verify the persisted card's board, phase, and deferred decision status either way.
|
|
410
511
|
|
|
411
512
|
Lifecycle, tool-result, and integration handlers may return `upsertLinkedWorkItem` targeting a different installed board. Linked cards enter that board's declared initial phase before moving to the requested phase. Existing cards cannot be reassigned to another board through either decision type. Targets are validated against their own installed board before acceptance and again before uncommitted deferred effects execute; a phase declared only on another board is not valid. Committed replay retains its recorded result and original `configVersion`.
|
|
412
513
|
|
|
@@ -414,12 +515,12 @@ Custom phase signals and persisted tool-result ingestion use the item's installe
|
|
|
414
515
|
|
|
415
516
|
### Custom boards in the Factory UI
|
|
416
517
|
|
|
417
|
-
`GET /web/factory/projects/:id/boards` returns the installed board catalog for an authorized project: each board's `id`, `title`, `initialPhase`, declaration-ordered `phases` (with `kind
|
|
518
|
+
`GET /web/factory/projects/:id/boards` returns the installed board catalog for an authorized project: 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:
|
|
418
519
|
|
|
419
520
|
- 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.
|
|
420
521
|
- 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.
|
|
421
522
|
- A card's persisted `board` decides which board it belongs to. UI actions cannot move a card to a different board.
|
|
422
|
-
- Settings › Skills groups built-in skills under Work and Review
|
|
523
|
+
- Settings › Skills groups built-in skills under Work and Review. For each custom board it shows the skill each phase runs (`runner.skill`) and the roles of phases that run no skill; those phases' kickoff instructions live in the board definition. Your app's other skills appear under App skills.
|
|
423
524
|
- Not yet board-aware: the Overview funnel and stage-hold metrics (Work-only), search scopes (Work/Review sessions), and the automation toggles that are specific to Work triage and Review. Custom-board cards still count toward in-flight totals and appear in activity and audit logs.
|
|
424
525
|
|
|
425
526
|
### Route intake to custom boards
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RuleFacts } from '../rules/rule-group.js';
|
|
2
|
+
import type { WorkItemRow } from '../storage/domains/work-items/base.js';
|
|
3
|
+
/** What a phase condition (`autoStartWhen`, `exitTool.autoApproveWhen`) can test about a card. */
|
|
4
|
+
export declare function cardRuleFacts(item: Pick<WorkItemRow, 'title' | 'metadata' | 'externalSource'>): RuleFacts;
|
|
5
|
+
//# sourceMappingURL=card-facts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-facts.d.ts","sourceRoot":"","sources":["../../src/boards/card-facts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAEzE,kGAAkG;AAClG,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,UAAU,GAAG,gBAAgB,CAAC,GAAG,SAAS,CAiBzG"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/boards/card-facts.ts
|
|
2
|
+
/** What a phase condition (`autoStartWhen`, `exitTool.autoApproveWhen`) can test about a card. */
|
|
3
|
+
function cardRuleFacts(item) {
|
|
4
|
+
const metadata = item.metadata ?? {};
|
|
5
|
+
const labels = Array.isArray(metadata.labels) ? metadata.labels.filter((label) => typeof label === "string") : [];
|
|
6
|
+
const source = item.externalSource;
|
|
7
|
+
return {
|
|
8
|
+
"item.labels": labels,
|
|
9
|
+
"item.title": item.title,
|
|
10
|
+
...typeof metadata.author === "string" ? { "item.author": metadata.author } : {},
|
|
11
|
+
...source ? {
|
|
12
|
+
"source.kind": source.type === "pull-request" ? "pull_request" : source.type,
|
|
13
|
+
"source.integration": source.integrationId
|
|
14
|
+
} : {}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export { cardRuleFacts };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=card-facts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-facts.js","names":[],"sources":["../../src/boards/card-facts.ts"],"sourcesContent":["import type { RuleFacts } from '../rules/rule-group.js';\nimport type { WorkItemRow } from '../storage/domains/work-items/base.js';\n\n/** What a phase condition (`autoStartWhen`, `exitTool.autoApproveWhen`) can test about a card. */\nexport function cardRuleFacts(item: Pick<WorkItemRow, 'title' | 'metadata' | 'externalSource'>): RuleFacts {\n const metadata = item.metadata ?? {};\n const labels = Array.isArray(metadata.labels)\n ? metadata.labels.filter((label): label is string => typeof label === 'string')\n : [];\n const source = item.externalSource;\n return {\n 'item.labels': labels,\n 'item.title': item.title,\n ...(typeof metadata.author === 'string' ? { 'item.author': metadata.author } : {}),\n ...(source\n ? {\n 'source.kind': source.type === 'pull-request' ? 'pull_request' : source.type,\n 'source.integration': source.integrationId,\n }\n : {}),\n };\n}\n"],"mappings":";;AAIA,SAAgB,cAAc,MAA6E;CACzG,MAAM,WAAW,KAAK,YAAY,CAAC;CACnC,MAAM,SAAS,MAAM,QAAQ,SAAS,MAAM,IACxC,SAAS,OAAO,QAAQ,UAA2B,OAAO,UAAU,QAAQ,IAC5E,CAAC;CACL,MAAM,SAAS,KAAK;CACpB,OAAO;EACL,eAAe;EACf,cAAc,KAAK;EACnB,GAAI,OAAO,SAAS,WAAW,WAAW,EAAE,eAAe,SAAS,OAAO,IAAI,CAAC;EAChF,GAAI,SACA;GACE,eAAe,OAAO,SAAS,iBAAiB,iBAAiB,OAAO;GACxE,sBAAsB,OAAO;EAC/B,IACA,CAAC;CACP;AACF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RuleFacts, RuleGroup } from '../rules/rule-group.js';
|
|
1
2
|
import type { FactoryGithubEventName, FactoryGithubRuleContext, FactoryGitLabEventName, FactoryGitLabRuleContext, FactoryIncidentioEventName, FactoryIncidentioRuleContext, FactoryJiraEventName, FactoryJiraRuleContext, FactoryLinearEventName, FactoryLinearRuleContext, FactoryRuleHandler, FactoryRuleSource, FactoryStageRuleContext, FactoryToolResultRuleContext } from '../rules/types.js';
|
|
2
3
|
import type { BoardTransitionPolicy } from './transition-policy.js';
|
|
3
4
|
type BoardPhaseHandlers = Partial<Record<FactoryRuleSource, FactoryRuleHandler<FactoryStageRuleContext>>>;
|
|
@@ -33,26 +34,112 @@ type ReadonlyFactoryBoardRules = Readonly<Record<string, Readonly<Partial<Record
|
|
|
33
34
|
/**
|
|
34
35
|
* What a phase means to the runtime.
|
|
35
36
|
* - `resting`: nobody is seated; a card waits for a person or an event.
|
|
36
|
-
* - `working`: an agent in
|
|
37
|
+
* - `working`: an agent in the phase's context carries the card; a person's move in arms autonomy.
|
|
37
38
|
* - `terminal`: the card is finished; sessions stop and held resources are released.
|
|
38
39
|
*/
|
|
39
40
|
export type BoardPhaseKind = 'resting' | 'working' | 'terminal';
|
|
41
|
+
/** The agent Factory runs every phase with. */
|
|
42
|
+
export declare const FACTORY_AGENT_ID = "code-agent";
|
|
43
|
+
/** The session context a working phase runs in when it names none. */
|
|
44
|
+
export declare const DEFAULT_PHASE_CONTEXT = "work";
|
|
45
|
+
/** Who runs a working phase, and with what. */
|
|
46
|
+
export interface BoardPhaseRunner {
|
|
47
|
+
/** Must be `code-agent`, the agent Factory runs; omitted means that agent. */
|
|
48
|
+
readonly agentId?: string;
|
|
49
|
+
/** Skill started when a card enters the phase from a source with no `onEnter` handler. */
|
|
50
|
+
readonly skill?: string;
|
|
51
|
+
/**
|
|
52
|
+
* The session the phase runs in. Phases naming the same context share one session per card;
|
|
53
|
+
* a different context gets its own. Defaults to `work`.
|
|
54
|
+
*/
|
|
55
|
+
readonly context?: string;
|
|
56
|
+
/** Appended to every run the phase starts. */
|
|
57
|
+
readonly instructions?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The tool whose successful call ends a working phase. The agent then moves the card itself with
|
|
61
|
+
* `factory_transition_work_item`, to one of the phase's `nextPhases`.
|
|
62
|
+
*/
|
|
63
|
+
export interface BoardPhaseExitTool {
|
|
64
|
+
readonly id: string;
|
|
65
|
+
/**
|
|
66
|
+
* Answer the approval the tool waits for without a person. Factory sessions run other tools
|
|
67
|
+
* without asking, so today this applies to `submit_plan`. Defaults to false.
|
|
68
|
+
*/
|
|
69
|
+
readonly autoApprove?: boolean;
|
|
70
|
+
/** With `autoApprove`, only cards this matches are approved without a person. */
|
|
71
|
+
readonly autoApproveWhen?: RuleGroup;
|
|
72
|
+
}
|
|
40
73
|
type BoardPhaseBase<PhaseId extends string> = {
|
|
41
|
-
readonly
|
|
74
|
+
readonly name?: string;
|
|
75
|
+
/** @deprecated Use `name`. */
|
|
76
|
+
readonly title?: string;
|
|
77
|
+
readonly description?: string;
|
|
78
|
+
/** Phases a card may move to from here. */
|
|
79
|
+
readonly nextPhases?: readonly PhaseId[];
|
|
80
|
+
/** @deprecated List the phase in `nextPhases`. */
|
|
42
81
|
readonly next?: PhaseId;
|
|
82
|
+
/** Named moves rules can choose by outcome; each target is also an allowed next phase. */
|
|
43
83
|
readonly outcomes?: Readonly<Record<string, PhaseId>>;
|
|
44
84
|
readonly onEnter?: ReadonlyBoardPhaseHandlers;
|
|
45
85
|
readonly onExit?: ReadonlyBoardPhaseHandlers;
|
|
46
86
|
};
|
|
47
|
-
|
|
48
|
-
readonly
|
|
87
|
+
type WorkingPhaseFields = {
|
|
88
|
+
readonly runner?: BoardPhaseRunner;
|
|
89
|
+
/** @deprecated Use `runner.context`. */
|
|
90
|
+
readonly role?: string;
|
|
91
|
+
/** Runs start without anyone approving them, even with the project's auto-run off. */
|
|
92
|
+
readonly autoStart?: boolean;
|
|
93
|
+
/** With `autoStart`, only cards this matches start on their own. */
|
|
94
|
+
readonly autoStartWhen?: RuleGroup;
|
|
95
|
+
/** A bare tool name is shorthand for `{ id }`, with nothing approved on a person's behalf. */
|
|
96
|
+
readonly exitTool?: string | BoardPhaseExitTool;
|
|
97
|
+
};
|
|
98
|
+
type NonWorkingPhaseFields = {
|
|
99
|
+
readonly runner?: never;
|
|
49
100
|
readonly role?: never;
|
|
50
|
-
|
|
101
|
+
readonly autoStart?: never;
|
|
102
|
+
readonly autoStartWhen?: never;
|
|
103
|
+
readonly exitTool?: never;
|
|
104
|
+
};
|
|
105
|
+
/** A phase as a board declares it. */
|
|
106
|
+
export type BoardPhaseDefinition<PhaseId extends string> = (BoardPhaseBase<PhaseId> & NonWorkingPhaseFields & {
|
|
107
|
+
readonly kind: 'resting';
|
|
108
|
+
}) | (BoardPhaseBase<PhaseId> & WorkingPhaseFields & {
|
|
51
109
|
readonly kind: 'working';
|
|
52
|
-
|
|
53
|
-
|
|
110
|
+
}) | (BoardPhaseBase<PhaseId> & NonWorkingPhaseFields & {
|
|
111
|
+
readonly kind: 'terminal';
|
|
112
|
+
});
|
|
113
|
+
type ResolvedPhaseBase<PhaseId extends string> = {
|
|
114
|
+
readonly name: string;
|
|
115
|
+
readonly description?: string;
|
|
116
|
+
/** Every phase a card may move to from here, including outcome targets. */
|
|
117
|
+
readonly nextPhases: readonly PhaseId[];
|
|
118
|
+
readonly outcomes?: Readonly<Record<string, PhaseId>>;
|
|
119
|
+
readonly onEnter?: ReadonlyBoardPhaseHandlers;
|
|
120
|
+
readonly onExit?: ReadonlyBoardPhaseHandlers;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* A phase as the board resolved it: deprecated fields are replaced by their new names, so
|
|
124
|
+
* only the new structure leaves `defineBoard()`, and a resolved phase can be declared again.
|
|
125
|
+
*/
|
|
126
|
+
export type BoardPhase<PhaseId extends string> = (ResolvedPhaseBase<PhaseId> & {
|
|
127
|
+
readonly kind: 'resting';
|
|
128
|
+
}) | (ResolvedPhaseBase<PhaseId> & {
|
|
129
|
+
readonly kind: 'working';
|
|
130
|
+
readonly runner: Readonly<BoardPhaseRunner & {
|
|
131
|
+
agentId: string;
|
|
132
|
+
context: string;
|
|
133
|
+
}>;
|
|
134
|
+
readonly autoStart?: boolean;
|
|
135
|
+
readonly autoStartWhen?: RuleGroup;
|
|
136
|
+
readonly exitTool?: Readonly<{
|
|
137
|
+
id: string;
|
|
138
|
+
autoApprove: boolean;
|
|
139
|
+
autoApproveWhen?: RuleGroup;
|
|
140
|
+
}>;
|
|
141
|
+
}) | (ResolvedPhaseBase<PhaseId> & {
|
|
54
142
|
readonly kind: 'terminal';
|
|
55
|
-
readonly role?: never;
|
|
56
143
|
});
|
|
57
144
|
export interface BoardTransition<PhaseId extends string> {
|
|
58
145
|
readonly outcome: string | null;
|
|
@@ -68,9 +155,10 @@ export type BoardSourceClosed<PhaseId extends string> = Readonly<{
|
|
|
68
155
|
}>;
|
|
69
156
|
export interface BoardDefinition<BoardId extends string, PhaseId extends string> {
|
|
70
157
|
readonly id: BoardId;
|
|
71
|
-
readonly
|
|
158
|
+
readonly name: string;
|
|
159
|
+
readonly description?: string;
|
|
72
160
|
readonly initialPhase: PhaseId;
|
|
73
|
-
readonly phases: Readonly<Record<PhaseId,
|
|
161
|
+
readonly phases: Readonly<Record<PhaseId, BoardPhase<PhaseId>>>;
|
|
74
162
|
readonly transitions: Readonly<Record<PhaseId, readonly BoardTransition<PhaseId>[]>>;
|
|
75
163
|
readonly rules: ReadonlyFactoryBoardRules;
|
|
76
164
|
/** Tool-result rules keyed by tool name; empty when the board declares none. */
|
|
@@ -85,14 +173,22 @@ export interface BoardDefinition<BoardId extends string, PhaseId extends string>
|
|
|
85
173
|
phaseKind(phase: string): BoardPhaseKind | undefined;
|
|
86
174
|
isWorking(phase: string): boolean;
|
|
87
175
|
isTerminal(phase: string): boolean;
|
|
88
|
-
/**
|
|
176
|
+
/** Session context of a working phase; undefined for resting/terminal/unknown phases. */
|
|
89
177
|
roleForPhase(phase: string): string | undefined;
|
|
90
|
-
/** First working phase, in declaration order,
|
|
178
|
+
/** First working phase, in declaration order, running in `role`'s context. */
|
|
91
179
|
phaseForRole(role: string): PhaseId | undefined;
|
|
180
|
+
/**
|
|
181
|
+
* Whether the phase's runs start without anyone approving them, for a card with these facts
|
|
182
|
+
* (`cardRuleFacts`). A phase with a start condition never starts on its own without facts.
|
|
183
|
+
*/
|
|
184
|
+
startsAutomatically(phase: string, facts?: RuleFacts): boolean;
|
|
92
185
|
}
|
|
93
186
|
type BoardConfig<BoardId extends string, Phases extends Record<string, BoardPhaseDefinition<keyof Phases & string>>> = {
|
|
94
187
|
id: BoardId;
|
|
95
|
-
|
|
188
|
+
name?: string;
|
|
189
|
+
/** @deprecated Use `name`. */
|
|
190
|
+
title?: string;
|
|
191
|
+
description?: string;
|
|
96
192
|
initialPhase: keyof Phases & string;
|
|
97
193
|
phases: Phases;
|
|
98
194
|
tools?: Record<string, BoardToolRule>;
|