@mastra/factory 0.8.0-alpha.13 → 0.8.0-alpha.14
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/CHANGELOG.md +209 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +11 -1
- package/dist/factory.js.map +1 -1
- package/dist/integrations/github/app-identity.d.ts +43 -0
- package/dist/integrations/github/app-identity.d.ts.map +1 -0
- package/dist/integrations/github/app-identity.js +62 -0
- package/dist/integrations/github/app-identity.js.map +1 -0
- package/dist/integrations/github/rules.d.ts +8 -0
- package/dist/integrations/github/rules.d.ts.map +1 -1
- package/dist/integrations/github/rules.js +30 -8
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/integrations/github/sandbox.d.ts +8 -5
- package/dist/integrations/github/sandbox.d.ts.map +1 -1
- package/dist/integrations/github/sandbox.js +36 -8
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/github/webhook.d.ts +20 -0
- package/dist/integrations/github/webhook.d.ts.map +1 -1
- package/dist/integrations/github/webhook.js +32 -5
- package/dist/integrations/github/webhook.js.map +1 -1
- package/dist/integrations/linear/rules.d.ts.map +1 -1
- package/dist/integrations/linear/rules.js +2 -1
- package/dist/integrations/linear/rules.js.map +1 -1
- package/dist/integrations/platform/github/event-worker.d.ts +2 -0
- package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
- package/dist/integrations/platform/github/event-worker.js +29 -7
- package/dist/integrations/platform/github/event-worker.js.map +1 -1
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +7 -1
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/routes/config.d.ts +4 -0
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +6 -0
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/knowledge.d.ts +152 -0
- package/dist/routes/knowledge.d.ts.map +1 -0
- package/dist/routes/knowledge.js +442 -0
- package/dist/routes/knowledge.js.map +1 -0
- package/dist/routes/surface.d.ts +1 -0
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +7 -0
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.d.ts.map +1 -1
- package/dist/routes/work-items.js +3 -1
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/binding-context.d.ts.map +1 -1
- package/dist/rules/binding-context.js +4 -1
- package/dist/rules/binding-context.js.map +1 -1
- package/dist/rules/defaults.d.ts.map +1 -1
- package/dist/rules/defaults.js +87 -4
- package/dist/rules/defaults.js.map +1 -1
- package/dist/rules/dispatcher.d.ts +6 -0
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +118 -16
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/processor.d.ts.map +1 -1
- package/dist/rules/processor.js +20 -7
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/resolve.d.ts +1 -0
- package/dist/rules/resolve.d.ts.map +1 -1
- package/dist/rules/resolve.js +3 -2
- package/dist/rules/resolve.js.map +1 -1
- package/dist/rules/start-coordinator.d.ts +2 -0
- package/dist/rules/start-coordinator.d.ts.map +1 -1
- package/dist/rules/start-coordinator.js +3 -1
- package/dist/rules/start-coordinator.js.map +1 -1
- package/dist/rules/terminal-cleanup.d.ts +23 -0
- package/dist/rules/terminal-cleanup.d.ts.map +1 -0
- package/dist/rules/terminal-cleanup.js +43 -0
- package/dist/rules/terminal-cleanup.js.map +1 -0
- package/dist/rules/tools.d.ts.map +1 -1
- package/dist/rules/tools.js +24 -2
- package/dist/rules/tools.js.map +1 -1
- package/dist/rules/transition-service.d.ts +3 -0
- package/dist/rules/transition-service.d.ts.map +1 -1
- package/dist/rules/transition-service.js +10 -6
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.d.ts +32 -3
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/types.js +2 -0
- package/dist/rules/types.js.map +1 -1
- package/dist/rules/validation.d.ts.map +1 -1
- package/dist/rules/validation.js +8 -3
- package/dist/rules/validation.js.map +1 -1
- package/dist/skills/service.d.ts +9 -0
- package/dist/skills/service.d.ts.map +1 -1
- package/dist/skills/service.js +10 -1
- package/dist/skills/service.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +67 -1
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +140 -12
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/factory-skills/factory-rereview/SKILL.md +1 -1
- package/factory-skills/factory-review/SKILL.md +1 -1
- package/package.json +7 -7
|
@@ -32,6 +32,18 @@ function isAgentActor(by) {
|
|
|
32
32
|
if (by === void 0) return false;
|
|
33
33
|
return by.startsWith("agent:") || by === "factory-tool-result-rule";
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Stages in which a bound run can still act on its work item. Mirrors the
|
|
37
|
+
* non-terminal subset of `FACTORY_RULE_STAGES` (rules/types.ts); bindings for
|
|
38
|
+
* items outside these stages are dead weight in the reconcile walk.
|
|
39
|
+
*/
|
|
40
|
+
const ACTIVE_RUN_BINDING_STAGES = /* @__PURE__ */ new Set([
|
|
41
|
+
"intake",
|
|
42
|
+
"triage",
|
|
43
|
+
"planning",
|
|
44
|
+
"execute",
|
|
45
|
+
"review"
|
|
46
|
+
]);
|
|
35
47
|
const WORK_ITEMS_SCHEMA = {
|
|
36
48
|
name: "work_items",
|
|
37
49
|
columns: {
|
|
@@ -58,6 +70,10 @@ const WORK_ITEMS_SCHEMA = {
|
|
|
58
70
|
type: "json",
|
|
59
71
|
nullable: true
|
|
60
72
|
},
|
|
73
|
+
autonomy_armed_at: {
|
|
74
|
+
type: "timestamp",
|
|
75
|
+
nullable: true
|
|
76
|
+
},
|
|
61
77
|
revision: {
|
|
62
78
|
type: "integer",
|
|
63
79
|
default: 1
|
|
@@ -101,6 +117,7 @@ function toWorkItem(row) {
|
|
|
101
117
|
stageHistory: row.stage_history,
|
|
102
118
|
sessions: row.sessions,
|
|
103
119
|
metadata: row.metadata,
|
|
120
|
+
autonomyArmedAt: row.autonomy_armed_at ?? null,
|
|
104
121
|
revision: row.revision,
|
|
105
122
|
createdBy: row.created_by,
|
|
106
123
|
createdAt: row.created_at,
|
|
@@ -116,6 +133,7 @@ function patchColumns(changes) {
|
|
|
116
133
|
...changes.stageHistory !== void 0 ? { stage_history: changes.stageHistory } : {},
|
|
117
134
|
...changes.sessions !== void 0 ? { sessions: changes.sessions } : {},
|
|
118
135
|
...changes.metadata !== void 0 ? { metadata: changes.metadata } : {},
|
|
136
|
+
...changes.autonomyArmedAt !== void 0 && changes.autonomyArmedAt !== null ? { autonomy_armed_at: changes.autonomyArmedAt } : {},
|
|
119
137
|
...changes.revision !== void 0 ? { revision: changes.revision } : {},
|
|
120
138
|
...changes.updatedAt !== void 0 ? { updated_at: changes.updatedAt } : {}
|
|
121
139
|
};
|
|
@@ -664,8 +682,10 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
|
|
|
664
682
|
reason = input.evaluation.reason;
|
|
665
683
|
return null;
|
|
666
684
|
}
|
|
667
|
-
|
|
685
|
+
const arm = input.armAutonomy === true && !existing.autonomyArmedAt;
|
|
686
|
+
if (existing.stages.length === 1 && existing.stages[0] === input.destinationStage) return arm ? patchColumns({ autonomyArmedAt: now }) : null;
|
|
668
687
|
return patchColumns({
|
|
688
|
+
...arm ? { autonomyArmedAt: now } : {},
|
|
669
689
|
stages: [input.destinationStage],
|
|
670
690
|
stageHistory: applyStageTransition(existing.stageHistory, existing.stages, [input.destinationStage], input.actorId, now),
|
|
671
691
|
revision: existing.revision + 1,
|
|
@@ -946,18 +966,37 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
|
|
|
946
966
|
});
|
|
947
967
|
return proposed && row ? toDeferredDecision(row) : null;
|
|
948
968
|
}
|
|
949
|
-
/**
|
|
969
|
+
/**
|
|
970
|
+
* Release an approved effect back to the dispatcher; only `proposed` rows are
|
|
971
|
+
* approvable. Approval is a person taking the item on, so the item's autonomy
|
|
972
|
+
* is armed in the same transaction — a crash cannot release the run while
|
|
973
|
+
* leaving its follow-up work parked for re-approval.
|
|
974
|
+
*/
|
|
950
975
|
async approveDeferredDecision(orgId, factoryProjectId, decisionId, now) {
|
|
951
|
-
return this
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
976
|
+
return this.storage.withTransaction(async (ops) => {
|
|
977
|
+
let settled = false;
|
|
978
|
+
const row = await ops.updateAtomic("factory_deferred_decisions", {
|
|
979
|
+
id: decisionId,
|
|
980
|
+
org_id: orgId,
|
|
981
|
+
factory_project_id: factoryProjectId
|
|
982
|
+
}, (current) => {
|
|
983
|
+
if (current.status !== "proposed") return null;
|
|
984
|
+
settled = true;
|
|
985
|
+
return {
|
|
986
|
+
status: "pending",
|
|
987
|
+
attempts: 0,
|
|
988
|
+
available_at: now,
|
|
989
|
+
approved_at: now,
|
|
990
|
+
updated_at: now
|
|
991
|
+
};
|
|
992
|
+
});
|
|
993
|
+
if (!settled || !row) return null;
|
|
994
|
+
const record = toDeferredDecision(row);
|
|
995
|
+
if (record.workItemId) await ops.updateAtomic("work_items", {
|
|
996
|
+
org_id: orgId,
|
|
997
|
+
id: record.workItemId
|
|
998
|
+
}, (current) => current.autonomy_armed_at ? null : { autonomy_armed_at: now });
|
|
999
|
+
return record;
|
|
961
1000
|
});
|
|
962
1001
|
}
|
|
963
1002
|
/** Retire a proposal nobody wants: `dismissed` is terminal, so the run never happens. */
|
|
@@ -972,6 +1011,29 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
|
|
|
972
1011
|
completed_at: now
|
|
973
1012
|
});
|
|
974
1013
|
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Retire proposals parked on a work item. A merged pull request (or an item
|
|
1016
|
+
* closed out any other way) leaves its queued runs with nothing left to do,
|
|
1017
|
+
* and they would otherwise sit on the card forever asking to be answered.
|
|
1018
|
+
*
|
|
1019
|
+
* Pass `role` to retire only the proposals a run now starting has overtaken:
|
|
1020
|
+
* a parked "start triage" is moot the moment triage is actually running.
|
|
1021
|
+
*/
|
|
1022
|
+
async dismissProposalsForWorkItem(input) {
|
|
1023
|
+
const rows = await this.#db.findMany("factory_deferred_decisions", {
|
|
1024
|
+
org_id: input.orgId,
|
|
1025
|
+
factory_project_id: input.factoryProjectId,
|
|
1026
|
+
work_item_id: input.workItemId,
|
|
1027
|
+
status: "proposed"
|
|
1028
|
+
});
|
|
1029
|
+
const dismissed = [];
|
|
1030
|
+
for (const row of rows) {
|
|
1031
|
+
if (input.role !== void 0 && toDeferredDecision(row).decision.role !== input.role) continue;
|
|
1032
|
+
const record = await this.dismissDeferredDecision(input.orgId, input.factoryProjectId, row.id, input.dismissedAt);
|
|
1033
|
+
if (record) dismissed.push(record);
|
|
1034
|
+
}
|
|
1035
|
+
return dismissed;
|
|
1036
|
+
}
|
|
975
1037
|
async #settleProposedDecision({ orgId, factoryProjectId, decisionId }, patch) {
|
|
976
1038
|
let settled = false;
|
|
977
1039
|
const row = await this.#db.updateAtomic("factory_deferred_decisions", {
|
|
@@ -1070,6 +1132,56 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
|
|
|
1070
1132
|
});
|
|
1071
1133
|
return revoked && row ? toBinding(row) : null;
|
|
1072
1134
|
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Revoke every active binding for one work item (all roles). Called from
|
|
1137
|
+
* terminal-stage cleanup so completed items stop paying the reconcile walk.
|
|
1138
|
+
* Returns the number of bindings revoked.
|
|
1139
|
+
*/
|
|
1140
|
+
async revokeRunBindingsForWorkItem(input) {
|
|
1141
|
+
return this.#db.updateMany("factory_run_bindings", {
|
|
1142
|
+
org_id: input.orgId,
|
|
1143
|
+
factory_project_id: input.factoryProjectId,
|
|
1144
|
+
work_item_id: input.workItemId,
|
|
1145
|
+
status: "active"
|
|
1146
|
+
}, {
|
|
1147
|
+
status: "revoked",
|
|
1148
|
+
revoked_at: input.revokedAt
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Revoke leaked/legacy active bindings: older than `olderThan`, or whose
|
|
1153
|
+
* work item is gone, malformed, or already terminal. Terminal-stage cleanup
|
|
1154
|
+
* handles bindings go-forward; this sweep drains anything that slipped past
|
|
1155
|
+
* it. Returns the number of bindings revoked.
|
|
1156
|
+
*/
|
|
1157
|
+
async revokeStaleRunBindings(input) {
|
|
1158
|
+
const bindings = await this.listActiveRunBindings();
|
|
1159
|
+
const itemCache = /* @__PURE__ */ new Map();
|
|
1160
|
+
let revoked = 0;
|
|
1161
|
+
for (const binding of bindings) {
|
|
1162
|
+
let stale = binding.createdAt.getTime() < input.olderThan.getTime();
|
|
1163
|
+
if (!stale) {
|
|
1164
|
+
const key = `${binding.orgId}:${binding.workItemId}`;
|
|
1165
|
+
let item = itemCache.get(key);
|
|
1166
|
+
if (item === void 0) {
|
|
1167
|
+
item = await this.get({
|
|
1168
|
+
orgId: binding.orgId,
|
|
1169
|
+
id: binding.workItemId
|
|
1170
|
+
});
|
|
1171
|
+
itemCache.set(key, item);
|
|
1172
|
+
}
|
|
1173
|
+
stale = !item || item.stages.length !== 1 || !ACTIVE_RUN_BINDING_STAGES.has(item.stages[0]) || item.factoryProjectId !== binding.factoryProjectId;
|
|
1174
|
+
}
|
|
1175
|
+
if (!stale) continue;
|
|
1176
|
+
if (await this.revokeRunBinding({
|
|
1177
|
+
orgId: binding.orgId,
|
|
1178
|
+
factoryProjectId: binding.factoryProjectId,
|
|
1179
|
+
bindingId: binding.id,
|
|
1180
|
+
revokedAt: input.now
|
|
1181
|
+
})) revoked += 1;
|
|
1182
|
+
}
|
|
1183
|
+
return revoked;
|
|
1184
|
+
}
|
|
1073
1185
|
/** Enumerate active bindings for the server-owned restart reconciler. */
|
|
1074
1186
|
async listActiveRunBindings() {
|
|
1075
1187
|
return (await this.#db.findMany("factory_run_bindings", { status: "active" })).map(toBinding);
|
|
@@ -1174,6 +1286,10 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
|
|
|
1174
1286
|
});
|
|
1175
1287
|
item = toRow(row);
|
|
1176
1288
|
}
|
|
1289
|
+
if (input.armAutonomy && !item.autonomyArmedAt) {
|
|
1290
|
+
const armedRow = await ops.updateAtomic("work_items", { id: item.id }, (current) => current.autonomy_armed_at ? null : { autonomy_armed_at: now });
|
|
1291
|
+
if (armedRow) item = toRow(armedRow);
|
|
1292
|
+
}
|
|
1177
1293
|
await ops.updateMany("factory_run_bindings", {
|
|
1178
1294
|
org_id: input.orgId,
|
|
1179
1295
|
factory_project_id: input.factoryProjectId,
|
|
@@ -1372,6 +1488,18 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
|
|
|
1372
1488
|
return this.#withProjectRelationTransaction(orgId, candidate.factory_project_id, run);
|
|
1373
1489
|
}
|
|
1374
1490
|
/**
|
|
1491
|
+
* Record that a person committed this item to the Factory. Only the first
|
|
1492
|
+
* time counts: the timestamp marks when the item stopped needing permission,
|
|
1493
|
+
* so later runs must not push it forward. Bumps no revision, because arming
|
|
1494
|
+
* is not a change anyone is editing against.
|
|
1495
|
+
*/
|
|
1496
|
+
async armAutonomy({ orgId, id, now }) {
|
|
1497
|
+
await this.#db.updateAtomic("work_items", {
|
|
1498
|
+
org_id: orgId,
|
|
1499
|
+
id
|
|
1500
|
+
}, (current) => current.autonomy_armed_at ? null : { autonomy_armed_at: now });
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1375
1503
|
* Drop the governance rows that materialized a source key so a deleted work item
|
|
1376
1504
|
* is not resurrected by the prior-ingress replay path on the next intake poll.
|
|
1377
1505
|
*/
|