@mastra/factory 0.2.1-alpha.3 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +3503 -3585
- package/dist/factory.js.map +1 -1
- package/dist/index.js +3503 -3585
- package/dist/index.js.map +1 -1
- package/dist/integrations/base.d.ts +13 -25
- package/dist/integrations/base.d.ts.map +1 -1
- package/dist/integrations/github/integration.d.ts.map +1 -1
- package/dist/integrations/github/integration.js +625 -217
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/routes.d.ts +1 -4
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +113 -203
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/rules.d.ts +30 -0
- package/dist/integrations/github/rules.d.ts.map +1 -0
- package/dist/{rules/github-service.js → integrations/github/rules.js} +27 -8
- package/dist/integrations/github/rules.js.map +1 -0
- package/dist/integrations/linear/agent-tools.js.map +1 -1
- package/dist/integrations/linear/integration.d.ts.map +1 -1
- package/dist/integrations/linear/integration.js +352 -3
- package/dist/integrations/linear/integration.js.map +1 -1
- package/dist/integrations/linear/routes.d.ts +2 -2
- package/dist/integrations/linear/routes.d.ts.map +1 -1
- package/dist/integrations/linear/routes.js +2 -2
- package/dist/integrations/linear/routes.js.map +1 -1
- package/dist/integrations/linear/rules.d.ts +42 -0
- package/dist/integrations/linear/rules.d.ts.map +1 -0
- package/dist/{rules/linear-service.js → integrations/linear/rules.js} +14 -4
- package/dist/integrations/linear/rules.js.map +1 -0
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +626 -218
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
- package/dist/integrations/platform/linear/integration.js +353 -3
- package/dist/integrations/platform/linear/integration.js.map +1 -1
- package/dist/routes/oauth.js +47 -41
- package/dist/routes/oauth.js.map +1 -1
- package/dist/routes/surface.d.ts +3 -1
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +271 -621
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +74 -75
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/storage/domains/work-items/metrics.js.map +1 -1
- package/package.json +7 -7
- package/dist/integrations/github/project-lock.d.ts +0 -100
- package/dist/integrations/github/project-lock.d.ts.map +0 -1
- package/dist/integrations/github/project-lock.js +0 -103
- package/dist/integrations/github/project-lock.js.map +0 -1
- package/dist/rules/github-service.d.ts +0 -29
- package/dist/rules/github-service.d.ts.map +0 -1
- package/dist/rules/github-service.js.map +0 -1
- package/dist/rules/linear-service.d.ts +0 -27
- package/dist/rules/linear-service.d.ts.map +0 -1
- package/dist/rules/linear-service.js.map +0 -1
package/dist/routes/surface.js
CHANGED
|
@@ -5797,7 +5797,7 @@ var init_errors = __esm({
|
|
|
5797
5797
|
});
|
|
5798
5798
|
|
|
5799
5799
|
// ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@libsql/hrana-client/0.10.0/56906f702e597dd372b3dd88d4aef2fcfb8f7d209d434be1f2455f1e7f8c6772/node_modules/@libsql/hrana-client/lib-esm/encoding/json/decode.js
|
|
5800
|
-
function
|
|
5800
|
+
function string(value) {
|
|
5801
5801
|
if (typeof value === "string") {
|
|
5802
5802
|
return value;
|
|
5803
5803
|
}
|
|
@@ -5811,13 +5811,13 @@ function stringOpt(value) {
|
|
|
5811
5811
|
}
|
|
5812
5812
|
throw typeError(value, "string or null");
|
|
5813
5813
|
}
|
|
5814
|
-
function
|
|
5814
|
+
function number(value) {
|
|
5815
5815
|
if (typeof value === "number") {
|
|
5816
5816
|
return value;
|
|
5817
5817
|
}
|
|
5818
5818
|
throw typeError(value, "number");
|
|
5819
5819
|
}
|
|
5820
|
-
function
|
|
5820
|
+
function boolean(value) {
|
|
5821
5821
|
if (typeof value === "boolean") {
|
|
5822
5822
|
return value;
|
|
5823
5823
|
}
|
|
@@ -5829,14 +5829,14 @@ function array(value) {
|
|
|
5829
5829
|
}
|
|
5830
5830
|
throw typeError(value, "array");
|
|
5831
5831
|
}
|
|
5832
|
-
function
|
|
5832
|
+
function object(value) {
|
|
5833
5833
|
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
5834
5834
|
return value;
|
|
5835
5835
|
}
|
|
5836
5836
|
throw typeError(value, "object");
|
|
5837
5837
|
}
|
|
5838
5838
|
function arrayObjectsMap(value, fun) {
|
|
5839
|
-
return array(value).map((elemValue) => fun(
|
|
5839
|
+
return array(value).map((elemValue) => fun(object(elemValue)));
|
|
5840
5840
|
}
|
|
5841
5841
|
function typeError(value, expected) {
|
|
5842
5842
|
if (value === void 0) {
|
|
@@ -5851,7 +5851,7 @@ function typeError(value, expected) {
|
|
|
5851
5851
|
return new ProtoError(`Expected ${expected}, received ${received}`);
|
|
5852
5852
|
}
|
|
5853
5853
|
function readJsonObject(value, fun) {
|
|
5854
|
-
return fun(
|
|
5854
|
+
return fun(object(value));
|
|
5855
5855
|
}
|
|
5856
5856
|
var init_decode = __esm({
|
|
5857
5857
|
"../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@libsql/hrana-client/0.10.0/56906f702e597dd372b3dd88d4aef2fcfb8f7d209d434be1f2455f1e7f8c6772/node_modules/@libsql/hrana-client/lib-esm/encoding/json/decode.js"() {
|
|
@@ -7531,14 +7531,14 @@ var init_protobuf_encode2 = __esm({
|
|
|
7531
7531
|
|
|
7532
7532
|
// ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@libsql/hrana-client/0.10.0/56906f702e597dd372b3dd88d4aef2fcfb8f7d209d434be1f2455f1e7f8c6772/node_modules/@libsql/hrana-client/lib-esm/shared/json_decode.js
|
|
7533
7533
|
function Error2(obj) {
|
|
7534
|
-
const message =
|
|
7534
|
+
const message = string(obj["message"]);
|
|
7535
7535
|
const code = stringOpt(obj["code"]);
|
|
7536
7536
|
return { message, code };
|
|
7537
7537
|
}
|
|
7538
7538
|
function StmtResult(obj) {
|
|
7539
7539
|
const cols = arrayObjectsMap(obj["cols"], Col);
|
|
7540
7540
|
const rows = array(obj["rows"]).map((rowObj) => arrayObjectsMap(rowObj, Value3));
|
|
7541
|
-
const affectedRowCount =
|
|
7541
|
+
const affectedRowCount = number(obj["affected_row_count"]);
|
|
7542
7542
|
const lastInsertRowidStr = stringOpt(obj["last_insert_rowid"]);
|
|
7543
7543
|
const lastInsertRowid = lastInsertRowidStr !== void 0 ? BigInt(lastInsertRowidStr) : void 0;
|
|
7544
7544
|
return { cols, rows, affectedRowCount, lastInsertRowid };
|
|
@@ -7552,37 +7552,37 @@ function BatchResult(obj) {
|
|
|
7552
7552
|
const stepResults = /* @__PURE__ */ new Map();
|
|
7553
7553
|
array(obj["step_results"]).forEach((value, i) => {
|
|
7554
7554
|
if (value !== null) {
|
|
7555
|
-
stepResults.set(i, StmtResult(
|
|
7555
|
+
stepResults.set(i, StmtResult(object(value)));
|
|
7556
7556
|
}
|
|
7557
7557
|
});
|
|
7558
7558
|
const stepErrors = /* @__PURE__ */ new Map();
|
|
7559
7559
|
array(obj["step_errors"]).forEach((value, i) => {
|
|
7560
7560
|
if (value !== null) {
|
|
7561
|
-
stepErrors.set(i, Error2(
|
|
7561
|
+
stepErrors.set(i, Error2(object(value)));
|
|
7562
7562
|
}
|
|
7563
7563
|
});
|
|
7564
7564
|
return { stepResults, stepErrors };
|
|
7565
7565
|
}
|
|
7566
7566
|
function CursorEntry(obj) {
|
|
7567
|
-
const type =
|
|
7567
|
+
const type = string(obj["type"]);
|
|
7568
7568
|
if (type === "step_begin") {
|
|
7569
|
-
const step =
|
|
7569
|
+
const step = number(obj["step"]);
|
|
7570
7570
|
const cols = arrayObjectsMap(obj["cols"], Col);
|
|
7571
7571
|
return { type: "step_begin", step, cols };
|
|
7572
7572
|
} else if (type === "step_end") {
|
|
7573
|
-
const affectedRowCount =
|
|
7573
|
+
const affectedRowCount = number(obj["affected_row_count"]);
|
|
7574
7574
|
const lastInsertRowidStr = stringOpt(obj["last_insert_rowid"]);
|
|
7575
7575
|
const lastInsertRowid = lastInsertRowidStr !== void 0 ? BigInt(lastInsertRowidStr) : void 0;
|
|
7576
7576
|
return { type: "step_end", affectedRowCount, lastInsertRowid };
|
|
7577
7577
|
} else if (type === "step_error") {
|
|
7578
|
-
const step =
|
|
7579
|
-
const error = Error2(
|
|
7578
|
+
const step = number(obj["step"]);
|
|
7579
|
+
const error = Error2(object(obj["error"]));
|
|
7580
7580
|
return { type: "step_error", step, error };
|
|
7581
7581
|
} else if (type === "row") {
|
|
7582
7582
|
const row = arrayObjectsMap(obj["row"], Value3);
|
|
7583
7583
|
return { type: "row", row };
|
|
7584
7584
|
} else if (type === "error") {
|
|
7585
|
-
const error = Error2(
|
|
7585
|
+
const error = Error2(object(obj["error"]));
|
|
7586
7586
|
return { type: "error", error };
|
|
7587
7587
|
} else {
|
|
7588
7588
|
throw new ProtoError("Unexpected type of CursorEntry");
|
|
@@ -7591,8 +7591,8 @@ function CursorEntry(obj) {
|
|
|
7591
7591
|
function DescribeResult(obj) {
|
|
7592
7592
|
const params = arrayObjectsMap(obj["params"], DescribeParam);
|
|
7593
7593
|
const cols = arrayObjectsMap(obj["cols"], DescribeCol);
|
|
7594
|
-
const isExplain =
|
|
7595
|
-
const isReadonly =
|
|
7594
|
+
const isExplain = boolean(obj["is_explain"]);
|
|
7595
|
+
const isReadonly = boolean(obj["is_readonly"]);
|
|
7596
7596
|
return { params, cols, isExplain, isReadonly };
|
|
7597
7597
|
}
|
|
7598
7598
|
function DescribeParam(obj) {
|
|
@@ -7600,23 +7600,23 @@ function DescribeParam(obj) {
|
|
|
7600
7600
|
return { name };
|
|
7601
7601
|
}
|
|
7602
7602
|
function DescribeCol(obj) {
|
|
7603
|
-
const name =
|
|
7603
|
+
const name = string(obj["name"]);
|
|
7604
7604
|
const decltype = stringOpt(obj["decltype"]);
|
|
7605
7605
|
return { name, decltype };
|
|
7606
7606
|
}
|
|
7607
7607
|
function Value3(obj) {
|
|
7608
|
-
const type =
|
|
7608
|
+
const type = string(obj["type"]);
|
|
7609
7609
|
if (type === "null") {
|
|
7610
7610
|
return null;
|
|
7611
7611
|
} else if (type === "integer") {
|
|
7612
|
-
const value =
|
|
7612
|
+
const value = string(obj["value"]);
|
|
7613
7613
|
return BigInt(value);
|
|
7614
7614
|
} else if (type === "float") {
|
|
7615
|
-
return
|
|
7615
|
+
return number(obj["value"]);
|
|
7616
7616
|
} else if (type === "text") {
|
|
7617
|
-
return
|
|
7617
|
+
return string(obj["value"]);
|
|
7618
7618
|
} else if (type === "blob") {
|
|
7619
|
-
return gBase64.toUint8Array(
|
|
7619
|
+
return gBase64.toUint8Array(string(obj["base64"]));
|
|
7620
7620
|
} else {
|
|
7621
7621
|
throw new ProtoError("Unexpected type of Value");
|
|
7622
7622
|
}
|
|
@@ -7632,35 +7632,35 @@ var init_json_decode = __esm({
|
|
|
7632
7632
|
|
|
7633
7633
|
// ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@libsql/hrana-client/0.10.0/56906f702e597dd372b3dd88d4aef2fcfb8f7d209d434be1f2455f1e7f8c6772/node_modules/@libsql/hrana-client/lib-esm/ws/json_decode.js
|
|
7634
7634
|
function ServerMsg(obj) {
|
|
7635
|
-
const type =
|
|
7635
|
+
const type = string(obj["type"]);
|
|
7636
7636
|
if (type === "hello_ok") {
|
|
7637
7637
|
return { type: "hello_ok" };
|
|
7638
7638
|
} else if (type === "hello_error") {
|
|
7639
|
-
const error = Error2(
|
|
7639
|
+
const error = Error2(object(obj["error"]));
|
|
7640
7640
|
return { type: "hello_error", error };
|
|
7641
7641
|
} else if (type === "response_ok") {
|
|
7642
|
-
const requestId =
|
|
7643
|
-
const response = Response(
|
|
7642
|
+
const requestId = number(obj["request_id"]);
|
|
7643
|
+
const response = Response(object(obj["response"]));
|
|
7644
7644
|
return { type: "response_ok", requestId, response };
|
|
7645
7645
|
} else if (type === "response_error") {
|
|
7646
|
-
const requestId =
|
|
7647
|
-
const error = Error2(
|
|
7646
|
+
const requestId = number(obj["request_id"]);
|
|
7647
|
+
const error = Error2(object(obj["error"]));
|
|
7648
7648
|
return { type: "response_error", requestId, error };
|
|
7649
7649
|
} else {
|
|
7650
7650
|
throw new ProtoError("Unexpected type of ServerMsg");
|
|
7651
7651
|
}
|
|
7652
7652
|
}
|
|
7653
7653
|
function Response(obj) {
|
|
7654
|
-
const type =
|
|
7654
|
+
const type = string(obj["type"]);
|
|
7655
7655
|
if (type === "open_stream") {
|
|
7656
7656
|
return { type: "open_stream" };
|
|
7657
7657
|
} else if (type === "close_stream") {
|
|
7658
7658
|
return { type: "close_stream" };
|
|
7659
7659
|
} else if (type === "execute") {
|
|
7660
|
-
const result = StmtResult(
|
|
7660
|
+
const result = StmtResult(object(obj["result"]));
|
|
7661
7661
|
return { type: "execute", result };
|
|
7662
7662
|
} else if (type === "batch") {
|
|
7663
|
-
const result = BatchResult(
|
|
7663
|
+
const result = BatchResult(object(obj["result"]));
|
|
7664
7664
|
return { type: "batch", result };
|
|
7665
7665
|
} else if (type === "open_cursor") {
|
|
7666
7666
|
return { type: "open_cursor" };
|
|
@@ -7668,19 +7668,19 @@ function Response(obj) {
|
|
|
7668
7668
|
return { type: "close_cursor" };
|
|
7669
7669
|
} else if (type === "fetch_cursor") {
|
|
7670
7670
|
const entries = arrayObjectsMap(obj["entries"], CursorEntry);
|
|
7671
|
-
const done =
|
|
7671
|
+
const done = boolean(obj["done"]);
|
|
7672
7672
|
return { type: "fetch_cursor", entries, done };
|
|
7673
7673
|
} else if (type === "sequence") {
|
|
7674
7674
|
return { type: "sequence" };
|
|
7675
7675
|
} else if (type === "describe") {
|
|
7676
|
-
const result = DescribeResult(
|
|
7676
|
+
const result = DescribeResult(object(obj["result"]));
|
|
7677
7677
|
return { type: "describe", result };
|
|
7678
7678
|
} else if (type === "store_sql") {
|
|
7679
7679
|
return { type: "store_sql" };
|
|
7680
7680
|
} else if (type === "close_sql") {
|
|
7681
7681
|
return { type: "close_sql" };
|
|
7682
7682
|
} else if (type === "get_autocommit") {
|
|
7683
|
-
const isAutocommit =
|
|
7683
|
+
const isAutocommit = boolean(obj["is_autocommit"]);
|
|
7684
7684
|
return { type: "get_autocommit", isAutocommit };
|
|
7685
7685
|
} else {
|
|
7686
7686
|
throw new ProtoError("Unexpected type of Response");
|
|
@@ -8427,38 +8427,38 @@ function PipelineRespBody(obj) {
|
|
|
8427
8427
|
return { baton, baseUrl, results };
|
|
8428
8428
|
}
|
|
8429
8429
|
function StreamResult(obj) {
|
|
8430
|
-
const type =
|
|
8430
|
+
const type = string(obj["type"]);
|
|
8431
8431
|
if (type === "ok") {
|
|
8432
|
-
const response = StreamResponse(
|
|
8432
|
+
const response = StreamResponse(object(obj["response"]));
|
|
8433
8433
|
return { type: "ok", response };
|
|
8434
8434
|
} else if (type === "error") {
|
|
8435
|
-
const error = Error2(
|
|
8435
|
+
const error = Error2(object(obj["error"]));
|
|
8436
8436
|
return { type: "error", error };
|
|
8437
8437
|
} else {
|
|
8438
8438
|
throw new ProtoError("Unexpected type of StreamResult");
|
|
8439
8439
|
}
|
|
8440
8440
|
}
|
|
8441
8441
|
function StreamResponse(obj) {
|
|
8442
|
-
const type =
|
|
8442
|
+
const type = string(obj["type"]);
|
|
8443
8443
|
if (type === "close") {
|
|
8444
8444
|
return { type: "close" };
|
|
8445
8445
|
} else if (type === "execute") {
|
|
8446
|
-
const result = StmtResult(
|
|
8446
|
+
const result = StmtResult(object(obj["result"]));
|
|
8447
8447
|
return { type: "execute", result };
|
|
8448
8448
|
} else if (type === "batch") {
|
|
8449
|
-
const result = BatchResult(
|
|
8449
|
+
const result = BatchResult(object(obj["result"]));
|
|
8450
8450
|
return { type: "batch", result };
|
|
8451
8451
|
} else if (type === "sequence") {
|
|
8452
8452
|
return { type: "sequence" };
|
|
8453
8453
|
} else if (type === "describe") {
|
|
8454
|
-
const result = DescribeResult(
|
|
8454
|
+
const result = DescribeResult(object(obj["result"]));
|
|
8455
8455
|
return { type: "describe", result };
|
|
8456
8456
|
} else if (type === "store_sql") {
|
|
8457
8457
|
return { type: "store_sql" };
|
|
8458
8458
|
} else if (type === "close_sql") {
|
|
8459
8459
|
return { type: "close_sql" };
|
|
8460
8460
|
} else if (type === "get_autocommit") {
|
|
8461
|
-
const isAutocommit =
|
|
8461
|
+
const isAutocommit = boolean(obj["is_autocommit"]);
|
|
8462
8462
|
return { type: "get_autocommit", isAutocommit };
|
|
8463
8463
|
} else {
|
|
8464
8464
|
throw new ProtoError("Unexpected type of StreamResponse");
|
|
@@ -10404,7 +10404,7 @@ __export(dist_exports, {
|
|
|
10404
10404
|
WorkspacesLibSQL: () => WorkspacesLibSQL
|
|
10405
10405
|
});
|
|
10406
10406
|
import { MastraError, ErrorCategory, ErrorDomain } from "@mastra/core/error";
|
|
10407
|
-
import { createVectorErrorId, AgentsStorage, AGENTS_SCHEMA, TABLE_AGENTS, AGENT_VERSIONS_SCHEMA, TABLE_AGENT_VERSIONS, createStorageErrorId, normalizePerPage, calculatePagination, BackgroundTasksStorage, TABLE_BACKGROUND_TASKS, TABLE_SCHEMAS, BlobStore, TABLE_SKILL_BLOBS, SKILL_BLOBS_SCHEMA, ChannelsStorage, TABLE_CHANNEL_INSTALLATIONS, TABLE_CHANNEL_CONFIG, DatasetsStorage, DATASETS_SCHEMA, TABLE_DATASETS, DATASET_ITEMS_SCHEMA, TABLE_DATASET_ITEMS, DATASET_VERSIONS_SCHEMA, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, ensureDate, safelyParseJSON, hasErrorCode, ExperimentsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, FavoritesStorage, FAVORITES_SCHEMA, TABLE_FAVORITES, TABLE_SKILLS, HarnessStorage, TABLE_HARNESS_SESSIONS, MCPClientsStorage, MCP_CLIENTS_SCHEMA, TABLE_MCP_CLIENTS, MCP_CLIENT_VERSIONS_SCHEMA, TABLE_MCP_CLIENT_VERSIONS, MCPServersStorage, MCP_SERVERS_SCHEMA, TABLE_MCP_SERVERS, MCP_SERVER_VERSIONS_SCHEMA, TABLE_MCP_SERVER_VERSIONS, MemoryStorage, TABLE_THREADS, TABLE_RESOURCES, TABLE_MESSAGES, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, NotificationsStorage, TABLE_NOTIFICATIONS, ObservabilityStorage, TABLE_SPANS, SPAN_SCHEMA, listTracesArgsSchema, toTraceSpans, PromptBlocksStorage, PROMPT_BLOCKS_SCHEMA, TABLE_PROMPT_BLOCKS, PROMPT_BLOCK_VERSIONS_SCHEMA, TABLE_PROMPT_BLOCK_VERSIONS, SchedulesStorage, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEDULES, ScorerDefinitionsStorage, SCORER_DEFINITIONS_SCHEMA, TABLE_SCORER_DEFINITIONS, SCORER_DEFINITION_VERSIONS_SCHEMA, TABLE_SCORER_DEFINITION_VERSIONS, ScoresStorage, TABLE_SCORERS, SCORERS_SCHEMA, transformScoreRow, SkillsStorage, SKILLS_SCHEMA, SKILL_VERSIONS_SCHEMA, TABLE_SKILL_VERSIONS, ThreadStateStorage, TABLE_THREAD_STATE, THREAD_STATE_SCHEMA, ToolProviderConnectionsStorage, TOOL_PROVIDER_CONNECTIONS_SCHEMA, TABLE_TOOL_PROVIDER_CONNECTIONS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, WorkspacesStorage, WORKSPACES_SCHEMA, TABLE_WORKSPACES, WORKSPACE_VERSIONS_SCHEMA, TABLE_WORKSPACE_VERSIONS, FactoryStorage, MastraCompositeStore, getSqlType, parseDuration, normalizeScheduleTarget, UniqueViolationError as UniqueViolationError2, TraceStatus, mergeWorkflowStepResult } from "@mastra/core/storage";
|
|
10407
|
+
import { createVectorErrorId, AgentsStorage, AGENTS_SCHEMA, TABLE_AGENTS, AGENT_VERSIONS_SCHEMA, TABLE_AGENT_VERSIONS, createStorageErrorId, normalizePerPage, calculatePagination, BackgroundTasksStorage, TABLE_BACKGROUND_TASKS, TABLE_SCHEMAS, BlobStore, TABLE_SKILL_BLOBS, SKILL_BLOBS_SCHEMA, ChannelsStorage, TABLE_CHANNEL_INSTALLATIONS, TABLE_CHANNEL_CONFIG, DatasetsStorage, DATASETS_SCHEMA, TABLE_DATASETS, DATASET_ITEMS_SCHEMA, TABLE_DATASET_ITEMS, DATASET_VERSIONS_SCHEMA, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, ensureDate, safelyParseJSON, hasErrorCode, ExperimentsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, FavoritesStorage, FAVORITES_SCHEMA, TABLE_FAVORITES, TABLE_SKILLS, HarnessStorage, TABLE_HARNESS_SESSIONS, MCPClientsStorage, MCP_CLIENTS_SCHEMA, TABLE_MCP_CLIENTS, MCP_CLIENT_VERSIONS_SCHEMA, TABLE_MCP_CLIENT_VERSIONS, MCPServersStorage, MCP_SERVERS_SCHEMA, TABLE_MCP_SERVERS, MCP_SERVER_VERSIONS_SCHEMA, TABLE_MCP_SERVER_VERSIONS, MemoryStorage, TABLE_THREADS, TABLE_RESOURCES, TABLE_MESSAGES, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, validateStorageMetadataFilter, NotificationsStorage, TABLE_NOTIFICATIONS, ObservabilityStorage, TABLE_SPANS, SPAN_SCHEMA, listTracesArgsSchema, toTraceSpans, PromptBlocksStorage, PROMPT_BLOCKS_SCHEMA, TABLE_PROMPT_BLOCKS, PROMPT_BLOCK_VERSIONS_SCHEMA, TABLE_PROMPT_BLOCK_VERSIONS, SchedulesStorage, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEDULES, ScorerDefinitionsStorage, SCORER_DEFINITIONS_SCHEMA, TABLE_SCORER_DEFINITIONS, SCORER_DEFINITION_VERSIONS_SCHEMA, TABLE_SCORER_DEFINITION_VERSIONS, ScoresStorage, TABLE_SCORERS, SCORERS_SCHEMA, transformScoreRow, SkillsStorage, SKILLS_SCHEMA, SKILL_VERSIONS_SCHEMA, TABLE_SKILL_VERSIONS, ThreadStateStorage, TABLE_THREAD_STATE, THREAD_STATE_SCHEMA, ToolProviderConnectionsStorage, TOOL_PROVIDER_CONNECTIONS_SCHEMA, TABLE_TOOL_PROVIDER_CONNECTIONS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, WorkspacesStorage, WORKSPACES_SCHEMA, TABLE_WORKSPACES, WORKSPACE_VERSIONS_SCHEMA, TABLE_WORKSPACE_VERSIONS, FactoryStorage, MastraCompositeStore, getSqlType, parseDuration, normalizeScheduleTarget, UniqueViolationError as UniqueViolationError2, TraceStatus, mergeWorkflowStepResult } from "@mastra/core/storage";
|
|
10408
10408
|
import { parseSqlIdentifier, parseFieldKey } from "@mastra/core/utils";
|
|
10409
10409
|
import { MastraVector, validateTopK, validateUpsertInput } from "@mastra/core/vector";
|
|
10410
10410
|
import { BaseFilterTranslator } from "@mastra/core/vector/filter";
|
|
@@ -11020,6 +11020,40 @@ function sessionToRecord(record) {
|
|
|
11020
11020
|
deletedAt: record.deletedAt ?? null
|
|
11021
11021
|
};
|
|
11022
11022
|
}
|
|
11023
|
+
function addSqliteMetadataFilter(conditions, params, metadataFilter) {
|
|
11024
|
+
if (!metadataFilter) return;
|
|
11025
|
+
for (const [key, value] of Object.entries(metadataFilter)) {
|
|
11026
|
+
const path = `$.metadata.${key}`;
|
|
11027
|
+
conditions.push(`CASE WHEN json_valid(content) THEN json_type(content, ?) IS NOT NULL ELSE 0 END`);
|
|
11028
|
+
params.push(path);
|
|
11029
|
+
addSqliteMetadataValuePredicate(conditions, params, path, value);
|
|
11030
|
+
}
|
|
11031
|
+
}
|
|
11032
|
+
function addSqliteMetadataValuePredicate(conditions, params, path, value) {
|
|
11033
|
+
if (value === null) {
|
|
11034
|
+
conditions.push(`CASE WHEN json_valid(content) THEN json_type(content, ?) = 'null' ELSE 0 END`);
|
|
11035
|
+
params.push(path);
|
|
11036
|
+
return;
|
|
11037
|
+
}
|
|
11038
|
+
if (typeof value === "string") {
|
|
11039
|
+
conditions.push(
|
|
11040
|
+
`CASE WHEN json_valid(content) THEN json_type(content, ?) = 'text' AND json_extract(content, ?) = ? ELSE 0 END`
|
|
11041
|
+
);
|
|
11042
|
+
params.push(path, path, value);
|
|
11043
|
+
return;
|
|
11044
|
+
}
|
|
11045
|
+
if (typeof value === "number") {
|
|
11046
|
+
conditions.push(
|
|
11047
|
+
`CASE WHEN json_valid(content) THEN json_type(content, ?) IN ('integer', 'real') AND json_extract(content, ?) = ? ELSE 0 END`
|
|
11048
|
+
);
|
|
11049
|
+
params.push(path, path, value);
|
|
11050
|
+
return;
|
|
11051
|
+
}
|
|
11052
|
+
conditions.push(
|
|
11053
|
+
`CASE WHEN json_valid(content) THEN json_type(content, ?) = ? AND json_extract(content, ?) = ? ELSE 0 END`
|
|
11054
|
+
);
|
|
11055
|
+
params.push(path, value ? "true" : "false", path, value ? 1 : 0);
|
|
11056
|
+
}
|
|
11023
11057
|
function parseJson2(value) {
|
|
11024
11058
|
if (value == null) return void 0;
|
|
11025
11059
|
if (typeof value === "string") {
|
|
@@ -11628,29 +11662,14 @@ var init_dist = __esm({
|
|
|
11628
11662
|
this.vectorIndexes = this.isMemoryDb ? Promise.resolve(/* @__PURE__ */ new Set()) : this.discoverVectorIndexes();
|
|
11629
11663
|
}
|
|
11630
11664
|
/**
|
|
11631
|
-
* Closes the underlying libsql client, releasing
|
|
11632
|
-
*
|
|
11633
|
-
* For local file databases, first runs PRAGMA wal_checkpoint(TRUNCATE) and
|
|
11634
|
-
* switches back to journal_mode=DELETE so the -wal and -shm sidecar files
|
|
11635
|
-
* are released promptly (mirrors LibSQLStore.close()).
|
|
11636
|
-
*
|
|
11637
|
-
* Remote (Turso) databases skip the WAL pragmas and just close the client.
|
|
11665
|
+
* Closes the underlying libsql client, releasing this vector store's OS file handles.
|
|
11638
11666
|
*
|
|
11639
11667
|
* Safe to call more than once; subsequent calls are no-ops.
|
|
11640
11668
|
*/
|
|
11641
11669
|
async close() {
|
|
11642
|
-
if (this.turso.closed) {
|
|
11643
|
-
|
|
11670
|
+
if (!this.turso.closed) {
|
|
11671
|
+
this.turso.close();
|
|
11644
11672
|
}
|
|
11645
|
-
if (this.turso.protocol === "file" && !this.isMemoryDb) {
|
|
11646
|
-
try {
|
|
11647
|
-
await this.turso.execute("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
11648
|
-
await this.turso.execute("PRAGMA journal_mode=DELETE;");
|
|
11649
|
-
} catch (err) {
|
|
11650
|
-
this.logger.warn("LibSQLVector: Failed to checkpoint WAL before close.", err);
|
|
11651
|
-
}
|
|
11652
|
-
}
|
|
11653
|
-
this.turso.close();
|
|
11654
11673
|
}
|
|
11655
11674
|
async discoverVectorIndexes() {
|
|
11656
11675
|
try {
|
|
@@ -17844,6 +17863,7 @@ Note: This migration may take some time for large tables.
|
|
|
17844
17863
|
}
|
|
17845
17864
|
const perPage = normalizePerPage(perPageInput, 40);
|
|
17846
17865
|
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
17866
|
+
const metadataFilter = validateStorageMetadataFilter(filter?.metadata);
|
|
17847
17867
|
try {
|
|
17848
17868
|
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
17849
17869
|
const orderByStatement = `ORDER BY "${field}" ${direction}`;
|
|
@@ -17868,6 +17888,7 @@ Note: This migration may take some time for large tables.
|
|
|
17868
17888
|
filter.dateRange.end instanceof Date ? filter.dateRange.end.toISOString() : filter.dateRange.end
|
|
17869
17889
|
);
|
|
17870
17890
|
}
|
|
17891
|
+
addSqliteMetadataFilter(conditions, queryParams, metadataFilter);
|
|
17871
17892
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
17872
17893
|
if (perPage === 0 && (!include || include.length === 0)) {
|
|
17873
17894
|
return { messages: [], total: 0, page, perPage: perPageForResponse, hasMore: false };
|
|
@@ -17897,6 +17918,7 @@ Note: This migration may take some time for large tables.
|
|
|
17897
17918
|
args: [...queryParams, limitValue, offset]
|
|
17898
17919
|
});
|
|
17899
17920
|
const messages = (dataResult.rows || []).map((row) => this.parseRow(row));
|
|
17921
|
+
const paginatedCount = messages.length;
|
|
17900
17922
|
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
17901
17923
|
return {
|
|
17902
17924
|
messages: [],
|
|
@@ -17925,7 +17947,7 @@ Note: This migration may take some time for large tables.
|
|
|
17925
17947
|
finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)
|
|
17926
17948
|
);
|
|
17927
17949
|
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
17928
|
-
const hasMore = perPageInput !== false && !allThreadMessagesReturned && offset + perPage < total;
|
|
17950
|
+
const hasMore = metadataFilter ? perPageInput !== false && offset + paginatedCount < total : perPageInput !== false && !allThreadMessagesReturned && offset + perPage < total;
|
|
17929
17951
|
return {
|
|
17930
17952
|
messages: finalMessages,
|
|
17931
17953
|
total,
|
|
@@ -17983,6 +18005,7 @@ Note: This migration may take some time for large tables.
|
|
|
17983
18005
|
}
|
|
17984
18006
|
const perPage = normalizePerPage(perPageInput, 40);
|
|
17985
18007
|
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
18008
|
+
const metadataFilter = validateStorageMetadataFilter(filter?.metadata);
|
|
17986
18009
|
try {
|
|
17987
18010
|
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
17988
18011
|
const orderByStatement = `ORDER BY "${field}" ${direction}`;
|
|
@@ -18004,6 +18027,7 @@ Note: This migration may take some time for large tables.
|
|
|
18004
18027
|
filter.dateRange.end instanceof Date ? filter.dateRange.end.toISOString() : filter.dateRange.end
|
|
18005
18028
|
);
|
|
18006
18029
|
}
|
|
18030
|
+
addSqliteMetadataFilter(conditions, queryParams, metadataFilter);
|
|
18007
18031
|
const whereClause = `WHERE ${conditions.join(" AND ")}`;
|
|
18008
18032
|
if (perPage === 0 && (!include || include.length === 0)) {
|
|
18009
18033
|
return { messages: [], total: 0, page, perPage: perPageForResponse, hasMore: false };
|
|
@@ -24409,32 +24433,14 @@ ${unreflectedContent}` : bufferedReflection;
|
|
|
24409
24433
|
await this.initDomainsSequentially();
|
|
24410
24434
|
}
|
|
24411
24435
|
/**
|
|
24412
|
-
* Closes the underlying libsql client, releasing
|
|
24413
|
-
*
|
|
24414
|
-
* For local file databases, first runs PRAGMA wal_checkpoint(TRUNCATE) and
|
|
24415
|
-
* switches back to journal_mode=DELETE so that Windows releases the -wal
|
|
24416
|
-
* and -shm sidecar files promptly. Without this, the handles stay open
|
|
24417
|
-
* until process exit, causing EBUSY errors when callers try to fs.rm the
|
|
24418
|
-
* storage directory after Mastra.shutdown().
|
|
24419
|
-
*
|
|
24420
|
-
* Remote (Turso) databases skip the WAL pragmas and just close the client.
|
|
24436
|
+
* Closes the underlying libsql client, releasing this store's OS file handles.
|
|
24421
24437
|
*
|
|
24422
24438
|
* Safe to call more than once; subsequent calls are no-ops.
|
|
24423
24439
|
*/
|
|
24424
24440
|
async close() {
|
|
24425
|
-
if (this.client.closed) {
|
|
24426
|
-
|
|
24441
|
+
if (!this.client.closed) {
|
|
24442
|
+
this.client.close();
|
|
24427
24443
|
}
|
|
24428
|
-
const isLocalFileDb = this.isLocalDb || this.client.protocol === "file";
|
|
24429
|
-
if (isLocalFileDb) {
|
|
24430
|
-
try {
|
|
24431
|
-
await this.client.execute("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
24432
|
-
await this.client.execute("PRAGMA journal_mode=DELETE;");
|
|
24433
|
-
} catch (err) {
|
|
24434
|
-
this.logger.warn("LibSQLStore: Failed to checkpoint WAL before close.", err);
|
|
24435
|
-
}
|
|
24436
|
-
}
|
|
24437
|
-
this.client.close();
|
|
24438
24444
|
}
|
|
24439
24445
|
};
|
|
24440
24446
|
LIBSQL_PROMPT = `When querying LibSQL Vector, you can ONLY use the operators listed below. Any other operators will be rejected.
|
|
@@ -24599,6 +24605,179 @@ async function ensureFactoryRuleSession(args) {
|
|
|
24599
24605
|
return { sessionId: session.sessionId, userId };
|
|
24600
24606
|
}
|
|
24601
24607
|
|
|
24608
|
+
// src/rules/start-coordinator.ts
|
|
24609
|
+
import { RequestContext } from "@mastra/core/request-context";
|
|
24610
|
+
import { formatSkillActivation } from "@mastra/core/workspace";
|
|
24611
|
+
var FactoryStartTransitionError = class extends Error {
|
|
24612
|
+
result;
|
|
24613
|
+
constructor(result) {
|
|
24614
|
+
super(result.reason);
|
|
24615
|
+
this.name = "FactoryStartTransitionError";
|
|
24616
|
+
this.result = result;
|
|
24617
|
+
}
|
|
24618
|
+
};
|
|
24619
|
+
function escapeSkillBoundary(value) {
|
|
24620
|
+
return value.replaceAll("</skill>", "</skill>");
|
|
24621
|
+
}
|
|
24622
|
+
async function resolveKickoffMessage(session, invocation) {
|
|
24623
|
+
if (!invocation) return null;
|
|
24624
|
+
if (invocation.type === "prompt") return invocation.prompt;
|
|
24625
|
+
const skills = session.getWorkspace().skills;
|
|
24626
|
+
await skills?.maybeRefresh();
|
|
24627
|
+
const skill = await skills?.get(invocation.skillName);
|
|
24628
|
+
if (!skill || skill["user-invocable"] === false) {
|
|
24629
|
+
throw new Error(`Skill not found: ${invocation.skillName}.`);
|
|
24630
|
+
}
|
|
24631
|
+
const args = invocation.arguments.trim();
|
|
24632
|
+
const content = `${formatSkillActivation(skill)}${args ? `
|
|
24633
|
+
|
|
24634
|
+
ARGUMENTS: ${args}` : ""}`.trim();
|
|
24635
|
+
return `<skill name="${skill.name}">
|
|
24636
|
+
${escapeSkillBoundary(content)}
|
|
24637
|
+
</skill>`;
|
|
24638
|
+
}
|
|
24639
|
+
async function resolveSourceSession(storage, request) {
|
|
24640
|
+
const session = await storage.sessions.getBySessionId(request.sessionId);
|
|
24641
|
+
if (!session || session.orgId !== request.orgId || session.userId !== request.userId) {
|
|
24642
|
+
throw new Error("Factory session not found");
|
|
24643
|
+
}
|
|
24644
|
+
const projectRepository = await storage.projectRepositories.get({
|
|
24645
|
+
orgId: request.orgId,
|
|
24646
|
+
id: session.projectRepositoryId
|
|
24647
|
+
});
|
|
24648
|
+
if (!projectRepository) throw new Error("Factory session repository not found");
|
|
24649
|
+
const connection = await storage.connections.get({ orgId: request.orgId, id: projectRepository.connectionId });
|
|
24650
|
+
if (!connection || connection.factoryProjectId !== request.factoryProjectId) {
|
|
24651
|
+
throw new Error("Factory session does not belong to this project");
|
|
24652
|
+
}
|
|
24653
|
+
return session;
|
|
24654
|
+
}
|
|
24655
|
+
async function configureThread(session, request) {
|
|
24656
|
+
const threadId = session.thread.requireId();
|
|
24657
|
+
await session.thread.rename({ title: request.threadTitle });
|
|
24658
|
+
const settings = { ...request.threadTags ?? {}, factorySessionId: request.sessionId };
|
|
24659
|
+
await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({ key, value })));
|
|
24660
|
+
return threadId;
|
|
24661
|
+
}
|
|
24662
|
+
async function applyMemorySettings(session, record) {
|
|
24663
|
+
if (record?.observerModelId) await session.om.observer.switchModel({ modelId: record.observerModelId });
|
|
24664
|
+
if (record?.reflectorModelId) await session.om.reflector.switchModel({ modelId: record.reflectorModelId });
|
|
24665
|
+
const state = {
|
|
24666
|
+
...record?.observationThreshold != null ? { observationThreshold: record.observationThreshold } : {},
|
|
24667
|
+
...record?.reflectionThreshold != null ? { reflectionThreshold: record.reflectionThreshold } : {},
|
|
24668
|
+
...record?.observeAttachments != null ? { observeAttachments: record.observeAttachments } : {}
|
|
24669
|
+
};
|
|
24670
|
+
if (Object.keys(state).length > 0) await session.state.set(state);
|
|
24671
|
+
}
|
|
24672
|
+
var FactoryStartCoordinator = class {
|
|
24673
|
+
#controller;
|
|
24674
|
+
#storage;
|
|
24675
|
+
#transitionService;
|
|
24676
|
+
#sourceControl;
|
|
24677
|
+
#memorySettings;
|
|
24678
|
+
constructor(controller, storage, transitionService, sourceControl, memorySettings) {
|
|
24679
|
+
this.#controller = controller;
|
|
24680
|
+
this.#storage = storage;
|
|
24681
|
+
this.#transitionService = transitionService;
|
|
24682
|
+
this.#sourceControl = sourceControl;
|
|
24683
|
+
this.#memorySettings = memorySettings;
|
|
24684
|
+
}
|
|
24685
|
+
async prepare(request) {
|
|
24686
|
+
const storage = this.#storage;
|
|
24687
|
+
if (!this.#sourceControl) throw new Error("Factory source control storage is unavailable");
|
|
24688
|
+
const sourceSession = await resolveSourceSession(this.#sourceControl, request);
|
|
24689
|
+
const requestContext = request.requestContext ?? new RequestContext();
|
|
24690
|
+
if (!request.requestContext) {
|
|
24691
|
+
requestContext.set("user", { workosId: request.userId, organizationId: request.orgId });
|
|
24692
|
+
}
|
|
24693
|
+
const sessionState = {
|
|
24694
|
+
factoryProjectId: request.factoryProjectId,
|
|
24695
|
+
projectRepositoryId: sourceSession.projectRepositoryId
|
|
24696
|
+
};
|
|
24697
|
+
const session = await this.#controller.createSession({
|
|
24698
|
+
id: sourceSession.sessionId,
|
|
24699
|
+
ownerId: request.userId,
|
|
24700
|
+
resourceId: sourceSession.sessionId,
|
|
24701
|
+
threadId: sourceSession.sessionId,
|
|
24702
|
+
requestContext,
|
|
24703
|
+
tags: sessionState
|
|
24704
|
+
});
|
|
24705
|
+
await session.state.set(sessionState);
|
|
24706
|
+
if (this.#memorySettings) {
|
|
24707
|
+
try {
|
|
24708
|
+
const record = await this.#memorySettings.get({ orgId: request.orgId, userId: request.userId });
|
|
24709
|
+
await applyMemorySettings(session, record);
|
|
24710
|
+
} catch (error) {
|
|
24711
|
+
console.warn("[Factory Start] Failed to apply observational-memory settings", {
|
|
24712
|
+
error: error instanceof Error ? error.message : String(error)
|
|
24713
|
+
});
|
|
24714
|
+
}
|
|
24715
|
+
}
|
|
24716
|
+
if (request.defaultModelId) {
|
|
24717
|
+
try {
|
|
24718
|
+
await session.model.switch({ modelId: request.defaultModelId });
|
|
24719
|
+
} catch (error) {
|
|
24720
|
+
console.warn("[Factory Start] Failed to apply factory default model", {
|
|
24721
|
+
modelId: request.defaultModelId,
|
|
24722
|
+
error: error instanceof Error ? error.message : String(error)
|
|
24723
|
+
});
|
|
24724
|
+
}
|
|
24725
|
+
}
|
|
24726
|
+
const threadId = await configureThread(session, request);
|
|
24727
|
+
const kickoffMessage = await resolveKickoffMessage(session, request.invocation);
|
|
24728
|
+
const prepared = await storage.prepareRunStart({
|
|
24729
|
+
orgId: request.orgId,
|
|
24730
|
+
userId: request.userId,
|
|
24731
|
+
factoryProjectId: request.factoryProjectId,
|
|
24732
|
+
workItem: { id: request.workItem.id, input: request.workItem.input },
|
|
24733
|
+
role: request.workItem.role,
|
|
24734
|
+
session: { sessionId: sourceSession.sessionId, branch: sourceSession.branch, threadId },
|
|
24735
|
+
resourceId: sourceSession.sessionId,
|
|
24736
|
+
kickoffKey: request.kickoffKey,
|
|
24737
|
+
kickoffMessage
|
|
24738
|
+
});
|
|
24739
|
+
await session.thread.setSetting({ key: "factoryWorkItemId", value: prepared.item.id });
|
|
24740
|
+
let revision = prepared.item.revision;
|
|
24741
|
+
if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {
|
|
24742
|
+
if (!this.#transitionService) throw new Error("Factory transition service is unavailable.");
|
|
24743
|
+
const transition = await this.#transitionService.transition({
|
|
24744
|
+
orgId: request.orgId,
|
|
24745
|
+
factoryProjectId: request.factoryProjectId,
|
|
24746
|
+
workItemId: prepared.item.id,
|
|
24747
|
+
board: prepared.item.externalSource?.type === "pull-request" ? "review" : "work",
|
|
24748
|
+
stage: request.destinationStage,
|
|
24749
|
+
expectedRevision: prepared.item.revision,
|
|
24750
|
+
actor: { type: "human", id: request.userId },
|
|
24751
|
+
ingress: { type: "human", identity: `start:${request.kickoffKey}:transition` },
|
|
24752
|
+
cause: "run_start"
|
|
24753
|
+
});
|
|
24754
|
+
if (transition.status === "rejected") {
|
|
24755
|
+
await storage.markPendingStart(prepared.binding.id, "failed", transition.reason);
|
|
24756
|
+
throw new FactoryStartTransitionError(transition);
|
|
24757
|
+
}
|
|
24758
|
+
revision = transition.revision;
|
|
24759
|
+
}
|
|
24760
|
+
if (kickoffMessage === null) {
|
|
24761
|
+
await storage.markPendingStart(prepared.binding.id, "sent");
|
|
24762
|
+
prepared.pendingStart.status = "sent";
|
|
24763
|
+
}
|
|
24764
|
+
return {
|
|
24765
|
+
workItemId: prepared.item.id,
|
|
24766
|
+
bindingId: prepared.binding.id,
|
|
24767
|
+
threadId,
|
|
24768
|
+
resourceId: sourceSession.sessionId,
|
|
24769
|
+
sessionId: sourceSession.sessionId,
|
|
24770
|
+
branch: sourceSession.branch,
|
|
24771
|
+
revision,
|
|
24772
|
+
kickoffStatus: prepared.pendingStart.status,
|
|
24773
|
+
replayed: prepared.replayed
|
|
24774
|
+
};
|
|
24775
|
+
}
|
|
24776
|
+
};
|
|
24777
|
+
|
|
24778
|
+
// src/rules/transition-service.ts
|
|
24779
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
24780
|
+
|
|
24602
24781
|
// src/rules/resolve.ts
|
|
24603
24782
|
function resolveFactoryStageRules(rules, input) {
|
|
24604
24783
|
if (input.fromStage === input.toStage && !input.initialEntry) return [];
|
|
@@ -24610,12 +24789,6 @@ function resolveFactoryStageRules(rules, input) {
|
|
|
24610
24789
|
if (onEnter) resolved.push({ phase: "enter", handler: onEnter });
|
|
24611
24790
|
return resolved;
|
|
24612
24791
|
}
|
|
24613
|
-
function resolveFactoryGithubRule(rules, event) {
|
|
24614
|
-
return rules.github[event]?.onEvent;
|
|
24615
|
-
}
|
|
24616
|
-
function resolveFactoryLinearRule(rules, event) {
|
|
24617
|
-
return rules.linear[event]?.onEvent;
|
|
24618
|
-
}
|
|
24619
24792
|
|
|
24620
24793
|
// src/rules/types.ts
|
|
24621
24794
|
var FACTORY_RULE_STAGES = ["intake", "triage", "planning", "execute", "review", "done", "canceled"];
|
|
@@ -24869,508 +25042,8 @@ function validateFactoryRuleDecisions(values, causalDepth = 0) {
|
|
|
24869
25042
|
return decisions;
|
|
24870
25043
|
}
|
|
24871
25044
|
|
|
24872
|
-
// src/rules/github-service.ts
|
|
24873
|
-
var TRUSTED_PERMISSIONS = /* @__PURE__ */ new Set(["write", "admin"]);
|
|
24874
|
-
var RULE_TIMEOUT_MS = 5e3;
|
|
24875
|
-
async function withRuleTimeout(promise) {
|
|
24876
|
-
let timeout;
|
|
24877
|
-
try {
|
|
24878
|
-
return await Promise.race([
|
|
24879
|
-
promise,
|
|
24880
|
-
new Promise((_, reject) => {
|
|
24881
|
-
timeout = setTimeout(() => reject(new Error("FACTORY_RULE_TIMEOUT")), RULE_TIMEOUT_MS);
|
|
24882
|
-
})
|
|
24883
|
-
]);
|
|
24884
|
-
} finally {
|
|
24885
|
-
if (timeout) clearTimeout(timeout);
|
|
24886
|
-
}
|
|
24887
|
-
}
|
|
24888
|
-
function object(value) {
|
|
24889
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
24890
|
-
}
|
|
24891
|
-
function string(value) {
|
|
24892
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
24893
|
-
}
|
|
24894
|
-
function number(value) {
|
|
24895
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
24896
|
-
}
|
|
24897
|
-
function boolean(value) {
|
|
24898
|
-
return typeof value === "boolean" ? value : void 0;
|
|
24899
|
-
}
|
|
24900
|
-
function eventName(parsed) {
|
|
24901
|
-
const action = string(parsed.payload.action);
|
|
24902
|
-
if (parsed.event === "issues" && action === "opened") return "issueOpened";
|
|
24903
|
-
if (parsed.event === "pull_request" && action === "opened") return "pullRequestOpened";
|
|
24904
|
-
if (parsed.event === "pull_request" && action === "synchronize") return "pullRequestUpdated";
|
|
24905
|
-
if (parsed.event === "pull_request" && action === "closed" && boolean(object(parsed.payload.pull_request)?.merged)) {
|
|
24906
|
-
return "pullRequestMerged";
|
|
24907
|
-
}
|
|
24908
|
-
if (parsed.event === "pull_request" && action === "review_requested") return "pullRequestReviewRequested";
|
|
24909
|
-
return void 0;
|
|
24910
|
-
}
|
|
24911
|
-
function canonicalSourceKey(kind, itemNumber) {
|
|
24912
|
-
return kind === "issue" ? `github-issue:${itemNumber}` : `github-pr:${itemNumber}`;
|
|
24913
|
-
}
|
|
24914
|
-
function legacySourceKey(repositoryId, kind, itemNumber) {
|
|
24915
|
-
return `github:${repositoryId}:${kind}:${itemNumber}`;
|
|
24916
|
-
}
|
|
24917
|
-
function provenanceTarget(repositoryId, pullRequestNumber) {
|
|
24918
|
-
return `factory-pr-provenance:${repositoryId}:${pullRequestNumber}`;
|
|
24919
|
-
}
|
|
24920
|
-
function workItemSource(item) {
|
|
24921
|
-
if (!item.externalSource) return "manual";
|
|
24922
|
-
return item.externalSource.type === "pull-request" ? "github-pr" : "github-issue";
|
|
24923
|
-
}
|
|
24924
|
-
function workItemSourceKey(item) {
|
|
24925
|
-
return item.externalSource?.externalId ?? null;
|
|
24926
|
-
}
|
|
24927
|
-
async function githubActor(github, input) {
|
|
24928
|
-
let trusted = false;
|
|
24929
|
-
try {
|
|
24930
|
-
const permission = await github.getRepositoryCollaboratorPermission(
|
|
24931
|
-
input.installationId,
|
|
24932
|
-
input.repository,
|
|
24933
|
-
input.login
|
|
24934
|
-
);
|
|
24935
|
-
trusted = permission !== void 0 && TRUSTED_PERMISSIONS.has(permission);
|
|
24936
|
-
} catch {
|
|
24937
|
-
trusted = false;
|
|
24938
|
-
}
|
|
24939
|
-
return { type: "github", login: input.login, trusted, factoryAuthored: input.factoryAuthored };
|
|
24940
|
-
}
|
|
24941
|
-
var FactoryGithubEventService = class {
|
|
24942
|
-
constructor(options) {
|
|
24943
|
-
this.options = options;
|
|
24944
|
-
}
|
|
24945
|
-
options;
|
|
24946
|
-
async ingest(parsed) {
|
|
24947
|
-
const event = eventName(parsed);
|
|
24948
|
-
const repository = object(parsed.payload.repository);
|
|
24949
|
-
const installationId = number(object(parsed.payload.installation)?.id);
|
|
24950
|
-
const repositoryId = number(repository?.id);
|
|
24951
|
-
const repositoryName = string(repository?.full_name);
|
|
24952
|
-
const login = string(object(parsed.payload.sender)?.login);
|
|
24953
|
-
if (!event || !installationId || !repositoryId || !repositoryName || !login) return { status: "ignored" };
|
|
24954
|
-
const projects = await this.options.sourceControl.projectRepositories.listByExternalRepository({
|
|
24955
|
-
installationExternalId: String(installationId),
|
|
24956
|
-
repositoryExternalId: String(repositoryId)
|
|
24957
|
-
});
|
|
24958
|
-
if (projects.length === 0) return { status: "ignored" };
|
|
24959
|
-
const results = [];
|
|
24960
|
-
for (const project of projects) {
|
|
24961
|
-
results.push(
|
|
24962
|
-
await this.#ingestProject(parsed, event, installationId, repositoryId, repositoryName, login, project)
|
|
24963
|
-
);
|
|
24964
|
-
}
|
|
24965
|
-
if (results.some((result) => result.status === "committed")) return { status: "committed" };
|
|
24966
|
-
if (results.some((result) => result.status === "replayed")) return { status: "replayed" };
|
|
24967
|
-
return results[0] ?? { status: "ignored" };
|
|
24968
|
-
}
|
|
24969
|
-
async #ingestProject(parsed, event, installationId, repositoryId, repositoryName, login, project) {
|
|
24970
|
-
const factoryProject = await this.options.projects.get({
|
|
24971
|
-
orgId: project.orgId,
|
|
24972
|
-
id: project.factoryProjectId
|
|
24973
|
-
});
|
|
24974
|
-
if (!factoryProject) return { status: "missing" };
|
|
24975
|
-
const issue = object(parsed.payload.issue);
|
|
24976
|
-
const pullRequest = object(parsed.payload.pull_request);
|
|
24977
|
-
const issueNumber = number(issue?.number);
|
|
24978
|
-
const pullRequestNumber = number(pullRequest?.number);
|
|
24979
|
-
const provenance = pullRequestNumber ? (await this.options.integrationStorage.subscriptions.listByTarget(
|
|
24980
|
-
provenanceTarget(repositoryId, pullRequestNumber),
|
|
24981
|
-
{ status: "active" }
|
|
24982
|
-
)).find((subscription) => subscription.orgId === project.orgId)?.data ?? null : null;
|
|
24983
|
-
const relatedItem = await this.#relatedItem(
|
|
24984
|
-
project.orgId,
|
|
24985
|
-
project.factoryProjectId,
|
|
24986
|
-
repositoryId,
|
|
24987
|
-
issueNumber,
|
|
24988
|
-
pullRequestNumber,
|
|
24989
|
-
string(object(pullRequest?.head)?.ref),
|
|
24990
|
-
provenance
|
|
24991
|
-
);
|
|
24992
|
-
const actor = await githubActor(this.options.github, {
|
|
24993
|
-
installationId,
|
|
24994
|
-
repository: repositoryName,
|
|
24995
|
-
login,
|
|
24996
|
-
factoryAuthored: provenance !== null
|
|
24997
|
-
});
|
|
24998
|
-
const context = {
|
|
24999
|
-
tenant: { orgId: project.orgId, projectId: project.factoryProjectId },
|
|
25000
|
-
actor,
|
|
25001
|
-
ingress: { type: "github", id: `${installationId}:${parsed.deliveryId}` },
|
|
25002
|
-
cause: `github.${event}`,
|
|
25003
|
-
causalChain: [],
|
|
25004
|
-
ruleSetVersion: this.options.rules.version,
|
|
25005
|
-
...relatedItem ? {
|
|
25006
|
-
item: {
|
|
25007
|
-
id: relatedItem.id,
|
|
25008
|
-
source: workItemSource(relatedItem),
|
|
25009
|
-
sourceKey: workItemSourceKey(relatedItem),
|
|
25010
|
-
parentWorkItemId: relatedItem.parentWorkItemId,
|
|
25011
|
-
title: relatedItem.title,
|
|
25012
|
-
url: relatedItem.externalSource?.url ?? null,
|
|
25013
|
-
stages: relatedItem.stages
|
|
25014
|
-
},
|
|
25015
|
-
board: relatedItem.externalSource?.type === "pull-request" ? "review" : "work",
|
|
25016
|
-
itemRevision: relatedItem.revision
|
|
25017
|
-
} : {},
|
|
25018
|
-
event,
|
|
25019
|
-
deliveryId: parsed.deliveryId,
|
|
25020
|
-
factory: { createdAt: factoryProject.createdAt.toISOString() },
|
|
25021
|
-
repository: { id: repositoryId, fullName: repositoryName },
|
|
25022
|
-
...issueNumber && string(issue?.title) && string(issue?.html_url) ? {
|
|
25023
|
-
issue: {
|
|
25024
|
-
number: issueNumber,
|
|
25025
|
-
title: string(issue?.title),
|
|
25026
|
-
url: string(issue?.html_url),
|
|
25027
|
-
...string(issue?.created_at) ? { createdAt: string(issue?.created_at) } : {}
|
|
25028
|
-
}
|
|
25029
|
-
} : {},
|
|
25030
|
-
...pullRequestNumber && string(pullRequest?.title) && string(pullRequest?.html_url) ? {
|
|
25031
|
-
pullRequest: {
|
|
25032
|
-
number: pullRequestNumber,
|
|
25033
|
-
title: string(pullRequest?.title),
|
|
25034
|
-
url: string(pullRequest?.html_url),
|
|
25035
|
-
...string(pullRequest?.created_at) ? { createdAt: string(pullRequest?.created_at) } : {},
|
|
25036
|
-
state: string(pullRequest?.state) === "closed" ? "closed" : "open",
|
|
25037
|
-
merged: boolean(pullRequest?.merged) ?? false,
|
|
25038
|
-
headBranch: string(object(pullRequest?.head)?.ref) ?? "",
|
|
25039
|
-
baseBranch: string(object(pullRequest?.base)?.ref) ?? ""
|
|
25040
|
-
}
|
|
25041
|
-
} : {},
|
|
25042
|
-
...object(parsed.payload.review) ? {
|
|
25043
|
-
review: {
|
|
25044
|
-
id: number(object(parsed.payload.review)?.id) ?? 0,
|
|
25045
|
-
state: string(object(parsed.payload.review)?.state) ?? "unknown",
|
|
25046
|
-
url: string(object(parsed.payload.review)?.html_url) ?? ""
|
|
25047
|
-
}
|
|
25048
|
-
} : {}
|
|
25049
|
-
};
|
|
25050
|
-
const rule = resolveFactoryGithubRule(this.options.rules, event);
|
|
25051
|
-
let decision;
|
|
25052
|
-
let decisions = [];
|
|
25053
|
-
let outcome = { status: "accepted" };
|
|
25054
|
-
try {
|
|
25055
|
-
decision = rule ? await withRuleTimeout(Promise.resolve(rule(Object.freeze(context)))) : void 0;
|
|
25056
|
-
if (decision?.type === "reject") {
|
|
25057
|
-
outcome = { status: "rejected", code: decision.code, reason: decision.reason };
|
|
25058
|
-
} else if (decision) {
|
|
25059
|
-
decisions = validateFactoryRuleDecisions([decision]).map((entry) => ({ ...entry }));
|
|
25060
|
-
}
|
|
25061
|
-
} catch (error) {
|
|
25062
|
-
const timedOut = error instanceof Error && error.message === "FACTORY_RULE_TIMEOUT";
|
|
25063
|
-
outcome = {
|
|
25064
|
-
status: "rejected",
|
|
25065
|
-
code: timedOut ? "timeout" : "rule_error",
|
|
25066
|
-
reason: timedOut ? "Factory rule evaluation timed out." : error instanceof Error ? error.message.slice(0, 2e3) : "Factory GitHub rule failed."
|
|
25067
|
-
};
|
|
25068
|
-
}
|
|
25069
|
-
const committed = await this.options.storage.commitRuleEvaluation({
|
|
25070
|
-
orgId: project.orgId,
|
|
25071
|
-
factoryProjectId: project.factoryProjectId,
|
|
25072
|
-
workItemId: relatedItem?.id ?? null,
|
|
25073
|
-
ingress: { identity: `${installationId}:${parsed.deliveryId}`, triggerType: `github.${event}` },
|
|
25074
|
-
ruleSetVersion: this.options.rules.version,
|
|
25075
|
-
expectedRevision: relatedItem?.revision ?? null,
|
|
25076
|
-
actor: { ...actor },
|
|
25077
|
-
outcome,
|
|
25078
|
-
decisions,
|
|
25079
|
-
causalChain: [],
|
|
25080
|
-
now: /* @__PURE__ */ new Date()
|
|
25081
|
-
});
|
|
25082
|
-
return { status: committed.status };
|
|
25083
|
-
}
|
|
25084
|
-
async #relatedItem(orgId, projectId, repositoryId, issueNumber, pullRequestNumber, pullRequestHeadBranch, provenance) {
|
|
25085
|
-
const items = await this.options.storage.list({ orgId, factoryProjectId: projectId });
|
|
25086
|
-
if (provenance) return items.find((item) => item.id === provenance.workItemId);
|
|
25087
|
-
if (issueNumber) {
|
|
25088
|
-
return items.find((item) => item.externalSource?.externalId === canonicalSourceKey("issue", issueNumber)) ?? items.find((item) => item.externalSource?.externalId === legacySourceKey(repositoryId, "issue", issueNumber));
|
|
25089
|
-
}
|
|
25090
|
-
if (pullRequestNumber) {
|
|
25091
|
-
return items.find((item) => item.externalSource?.externalId === canonicalSourceKey("pull-request", pullRequestNumber)) ?? items.find(
|
|
25092
|
-
(item) => item.externalSource?.externalId === legacySourceKey(repositoryId, "pull-request", pullRequestNumber)
|
|
25093
|
-
) ?? // Provenance fallback: a PR pushed from a work item's session branch
|
|
25094
|
-
// belongs to that item even when no gh-pr-create provenance was
|
|
25095
|
-
// recorded (session predating state seeding, or the PR was opened
|
|
25096
|
-
// outside the tracked tool call). Session branches are per-item
|
|
25097
|
-
// (`factory/issue-N`), so a head-branch match is unambiguous.
|
|
25098
|
-
(pullRequestHeadBranch ? items.find(
|
|
25099
|
-
(item) => item.externalSource?.type !== "pull-request" && Object.values(item.sessions).some((session) => session.branch === pullRequestHeadBranch)
|
|
25100
|
-
) : void 0);
|
|
25101
|
-
}
|
|
25102
|
-
return void 0;
|
|
25103
|
-
}
|
|
25104
|
-
};
|
|
25105
|
-
|
|
25106
|
-
// src/rules/linear-service.ts
|
|
25107
|
-
var RULE_TIMEOUT_MS2 = 5e3;
|
|
25108
|
-
async function withRuleTimeout2(promise) {
|
|
25109
|
-
let timeout;
|
|
25110
|
-
try {
|
|
25111
|
-
return await Promise.race([
|
|
25112
|
-
promise,
|
|
25113
|
-
new Promise((_, reject) => {
|
|
25114
|
-
timeout = setTimeout(() => reject(new Error("FACTORY_RULE_TIMEOUT")), RULE_TIMEOUT_MS2);
|
|
25115
|
-
})
|
|
25116
|
-
]);
|
|
25117
|
-
} finally {
|
|
25118
|
-
if (timeout) clearTimeout(timeout);
|
|
25119
|
-
}
|
|
25120
|
-
}
|
|
25121
|
-
var FactoryLinearIssueService = class {
|
|
25122
|
-
constructor(options) {
|
|
25123
|
-
this.options = options;
|
|
25124
|
-
}
|
|
25125
|
-
options;
|
|
25126
|
-
async ingest(input) {
|
|
25127
|
-
const project = await this.options.projects.get({ orgId: input.orgId, id: input.factoryProjectId });
|
|
25128
|
-
if (!project) return { status: "missing", ingested: 0 };
|
|
25129
|
-
const items = await this.options.storage.list({ orgId: input.orgId, factoryProjectId: input.factoryProjectId });
|
|
25130
|
-
const itemsBySourceKey = new Map(items.map((item) => [item.externalSource?.externalId, item]));
|
|
25131
|
-
const statuses = [];
|
|
25132
|
-
for (const issue of input.issues) {
|
|
25133
|
-
statuses.push(await this.#ingestIssue(input, issue, itemsBySourceKey.get(`linear:${issue.identifier}`)));
|
|
25134
|
-
}
|
|
25135
|
-
if (statuses.some((status) => status === "committed")) return { status: "committed", ingested: statuses.length };
|
|
25136
|
-
if (statuses.some((status) => status === "replayed")) return { status: "replayed", ingested: statuses.length };
|
|
25137
|
-
return { status: "missing", ingested: statuses.length };
|
|
25138
|
-
}
|
|
25139
|
-
async #ingestIssue(input, issue, relatedItem) {
|
|
25140
|
-
const ingressId = `linear:${issue.id}:${issue.updatedAt}`;
|
|
25141
|
-
const actor = { type: "human", id: input.userId };
|
|
25142
|
-
const context = {
|
|
25143
|
-
tenant: { orgId: input.orgId, projectId: input.factoryProjectId },
|
|
25144
|
-
actor,
|
|
25145
|
-
ingress: { type: "linear", id: ingressId },
|
|
25146
|
-
cause: "linear.issueObserved",
|
|
25147
|
-
causalChain: [],
|
|
25148
|
-
ruleSetVersion: this.options.rules.version,
|
|
25149
|
-
...relatedItem ? {
|
|
25150
|
-
item: {
|
|
25151
|
-
id: relatedItem.id,
|
|
25152
|
-
source: "linear-issue",
|
|
25153
|
-
sourceKey: relatedItem.externalSource?.externalId ?? null,
|
|
25154
|
-
parentWorkItemId: relatedItem.parentWorkItemId,
|
|
25155
|
-
title: relatedItem.title,
|
|
25156
|
-
url: relatedItem.externalSource?.url ?? null,
|
|
25157
|
-
stages: relatedItem.stages
|
|
25158
|
-
},
|
|
25159
|
-
board: "work",
|
|
25160
|
-
itemRevision: relatedItem.revision
|
|
25161
|
-
} : {},
|
|
25162
|
-
event: "issueObserved",
|
|
25163
|
-
issue
|
|
25164
|
-
};
|
|
25165
|
-
const rule = resolveFactoryLinearRule(this.options.rules, context.event);
|
|
25166
|
-
let decision;
|
|
25167
|
-
let decisions = [];
|
|
25168
|
-
let outcome = { status: "accepted" };
|
|
25169
|
-
try {
|
|
25170
|
-
decision = rule ? await withRuleTimeout2(Promise.resolve(rule(Object.freeze(context)))) : void 0;
|
|
25171
|
-
if (decision?.type === "reject") {
|
|
25172
|
-
outcome = { status: "rejected", code: decision.code, reason: decision.reason };
|
|
25173
|
-
} else if (decision) {
|
|
25174
|
-
decisions = validateFactoryRuleDecisions([decision]).map((entry) => ({ ...entry }));
|
|
25175
|
-
}
|
|
25176
|
-
} catch (error) {
|
|
25177
|
-
const timedOut = error instanceof Error && error.message === "FACTORY_RULE_TIMEOUT";
|
|
25178
|
-
outcome = {
|
|
25179
|
-
status: "rejected",
|
|
25180
|
-
code: timedOut ? "timeout" : "rule_error",
|
|
25181
|
-
reason: timedOut ? "Factory rule evaluation timed out." : error instanceof Error ? error.message.slice(0, 2e3) : "Factory Linear rule failed."
|
|
25182
|
-
};
|
|
25183
|
-
}
|
|
25184
|
-
const committed = await this.options.storage.commitRuleEvaluation({
|
|
25185
|
-
orgId: input.orgId,
|
|
25186
|
-
factoryProjectId: input.factoryProjectId,
|
|
25187
|
-
workItemId: relatedItem?.id ?? null,
|
|
25188
|
-
ingress: { identity: ingressId, triggerType: "linear.issueObserved" },
|
|
25189
|
-
ruleSetVersion: this.options.rules.version,
|
|
25190
|
-
expectedRevision: relatedItem?.revision ?? null,
|
|
25191
|
-
actor,
|
|
25192
|
-
outcome,
|
|
25193
|
-
decisions,
|
|
25194
|
-
causalChain: [],
|
|
25195
|
-
now: /* @__PURE__ */ new Date()
|
|
25196
|
-
});
|
|
25197
|
-
return committed.status;
|
|
25198
|
-
}
|
|
25199
|
-
};
|
|
25200
|
-
|
|
25201
|
-
// src/rules/start-coordinator.ts
|
|
25202
|
-
import { RequestContext } from "@mastra/core/request-context";
|
|
25203
|
-
import { formatSkillActivation } from "@mastra/core/workspace";
|
|
25204
|
-
var FactoryStartTransitionError = class extends Error {
|
|
25205
|
-
result;
|
|
25206
|
-
constructor(result) {
|
|
25207
|
-
super(result.reason);
|
|
25208
|
-
this.name = "FactoryStartTransitionError";
|
|
25209
|
-
this.result = result;
|
|
25210
|
-
}
|
|
25211
|
-
};
|
|
25212
|
-
function escapeSkillBoundary(value) {
|
|
25213
|
-
return value.replaceAll("</skill>", "</skill>");
|
|
25214
|
-
}
|
|
25215
|
-
async function resolveKickoffMessage(session, invocation) {
|
|
25216
|
-
if (!invocation) return null;
|
|
25217
|
-
if (invocation.type === "prompt") return invocation.prompt;
|
|
25218
|
-
const skills = session.getWorkspace().skills;
|
|
25219
|
-
await skills?.maybeRefresh();
|
|
25220
|
-
const skill = await skills?.get(invocation.skillName);
|
|
25221
|
-
if (!skill || skill["user-invocable"] === false) {
|
|
25222
|
-
throw new Error(`Skill not found: ${invocation.skillName}.`);
|
|
25223
|
-
}
|
|
25224
|
-
const args = invocation.arguments.trim();
|
|
25225
|
-
const content = `${formatSkillActivation(skill)}${args ? `
|
|
25226
|
-
|
|
25227
|
-
ARGUMENTS: ${args}` : ""}`.trim();
|
|
25228
|
-
return `<skill name="${skill.name}">
|
|
25229
|
-
${escapeSkillBoundary(content)}
|
|
25230
|
-
</skill>`;
|
|
25231
|
-
}
|
|
25232
|
-
async function resolveSourceSession(storage, request) {
|
|
25233
|
-
const session = await storage.sessions.getBySessionId(request.sessionId);
|
|
25234
|
-
if (!session || session.orgId !== request.orgId || session.userId !== request.userId) {
|
|
25235
|
-
throw new Error("Factory session not found");
|
|
25236
|
-
}
|
|
25237
|
-
const projectRepository = await storage.projectRepositories.get({
|
|
25238
|
-
orgId: request.orgId,
|
|
25239
|
-
id: session.projectRepositoryId
|
|
25240
|
-
});
|
|
25241
|
-
if (!projectRepository) throw new Error("Factory session repository not found");
|
|
25242
|
-
const connection = await storage.connections.get({ orgId: request.orgId, id: projectRepository.connectionId });
|
|
25243
|
-
if (!connection || connection.factoryProjectId !== request.factoryProjectId) {
|
|
25244
|
-
throw new Error("Factory session does not belong to this project");
|
|
25245
|
-
}
|
|
25246
|
-
return session;
|
|
25247
|
-
}
|
|
25248
|
-
async function configureThread(session, request) {
|
|
25249
|
-
const threadId = session.thread.requireId();
|
|
25250
|
-
await session.thread.rename({ title: request.threadTitle });
|
|
25251
|
-
const settings = { ...request.threadTags ?? {}, factorySessionId: request.sessionId };
|
|
25252
|
-
await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({ key, value })));
|
|
25253
|
-
return threadId;
|
|
25254
|
-
}
|
|
25255
|
-
async function applyMemorySettings(session, record) {
|
|
25256
|
-
if (record?.observerModelId) await session.om.observer.switchModel({ modelId: record.observerModelId });
|
|
25257
|
-
if (record?.reflectorModelId) await session.om.reflector.switchModel({ modelId: record.reflectorModelId });
|
|
25258
|
-
const state = {
|
|
25259
|
-
...record?.observationThreshold != null ? { observationThreshold: record.observationThreshold } : {},
|
|
25260
|
-
...record?.reflectionThreshold != null ? { reflectionThreshold: record.reflectionThreshold } : {},
|
|
25261
|
-
...record?.observeAttachments != null ? { observeAttachments: record.observeAttachments } : {}
|
|
25262
|
-
};
|
|
25263
|
-
if (Object.keys(state).length > 0) await session.state.set(state);
|
|
25264
|
-
}
|
|
25265
|
-
var FactoryStartCoordinator = class {
|
|
25266
|
-
#controller;
|
|
25267
|
-
#storage;
|
|
25268
|
-
#transitionService;
|
|
25269
|
-
#sourceControl;
|
|
25270
|
-
#memorySettings;
|
|
25271
|
-
constructor(controller, storage, transitionService, sourceControl, memorySettings) {
|
|
25272
|
-
this.#controller = controller;
|
|
25273
|
-
this.#storage = storage;
|
|
25274
|
-
this.#transitionService = transitionService;
|
|
25275
|
-
this.#sourceControl = sourceControl;
|
|
25276
|
-
this.#memorySettings = memorySettings;
|
|
25277
|
-
}
|
|
25278
|
-
async prepare(request) {
|
|
25279
|
-
const storage = this.#storage;
|
|
25280
|
-
if (!this.#sourceControl) throw new Error("Factory source control storage is unavailable");
|
|
25281
|
-
const sourceSession = await resolveSourceSession(this.#sourceControl, request);
|
|
25282
|
-
const requestContext = request.requestContext ?? new RequestContext();
|
|
25283
|
-
if (!request.requestContext) {
|
|
25284
|
-
requestContext.set("user", { workosId: request.userId, organizationId: request.orgId });
|
|
25285
|
-
}
|
|
25286
|
-
const sessionState = {
|
|
25287
|
-
factoryProjectId: request.factoryProjectId,
|
|
25288
|
-
projectRepositoryId: sourceSession.projectRepositoryId
|
|
25289
|
-
};
|
|
25290
|
-
const session = await this.#controller.createSession({
|
|
25291
|
-
id: sourceSession.sessionId,
|
|
25292
|
-
ownerId: request.userId,
|
|
25293
|
-
resourceId: sourceSession.sessionId,
|
|
25294
|
-
threadId: sourceSession.sessionId,
|
|
25295
|
-
requestContext,
|
|
25296
|
-
tags: sessionState
|
|
25297
|
-
});
|
|
25298
|
-
await session.state.set(sessionState);
|
|
25299
|
-
if (this.#memorySettings) {
|
|
25300
|
-
try {
|
|
25301
|
-
const record = await this.#memorySettings.get({ orgId: request.orgId, userId: request.userId });
|
|
25302
|
-
await applyMemorySettings(session, record);
|
|
25303
|
-
} catch (error) {
|
|
25304
|
-
console.warn("[Factory Start] Failed to apply observational-memory settings", {
|
|
25305
|
-
error: error instanceof Error ? error.message : String(error)
|
|
25306
|
-
});
|
|
25307
|
-
}
|
|
25308
|
-
}
|
|
25309
|
-
if (request.defaultModelId) {
|
|
25310
|
-
try {
|
|
25311
|
-
await session.model.switch({ modelId: request.defaultModelId });
|
|
25312
|
-
} catch (error) {
|
|
25313
|
-
console.warn("[Factory Start] Failed to apply factory default model", {
|
|
25314
|
-
modelId: request.defaultModelId,
|
|
25315
|
-
error: error instanceof Error ? error.message : String(error)
|
|
25316
|
-
});
|
|
25317
|
-
}
|
|
25318
|
-
}
|
|
25319
|
-
const threadId = await configureThread(session, request);
|
|
25320
|
-
const kickoffMessage = await resolveKickoffMessage(session, request.invocation);
|
|
25321
|
-
const prepared = await storage.prepareRunStart({
|
|
25322
|
-
orgId: request.orgId,
|
|
25323
|
-
userId: request.userId,
|
|
25324
|
-
factoryProjectId: request.factoryProjectId,
|
|
25325
|
-
workItem: { id: request.workItem.id, input: request.workItem.input },
|
|
25326
|
-
role: request.workItem.role,
|
|
25327
|
-
session: { sessionId: sourceSession.sessionId, branch: sourceSession.branch, threadId },
|
|
25328
|
-
resourceId: sourceSession.sessionId,
|
|
25329
|
-
kickoffKey: request.kickoffKey,
|
|
25330
|
-
kickoffMessage
|
|
25331
|
-
});
|
|
25332
|
-
await session.thread.setSetting({ key: "factoryWorkItemId", value: prepared.item.id });
|
|
25333
|
-
let revision = prepared.item.revision;
|
|
25334
|
-
if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {
|
|
25335
|
-
if (!this.#transitionService) throw new Error("Factory transition service is unavailable.");
|
|
25336
|
-
const transition = await this.#transitionService.transition({
|
|
25337
|
-
orgId: request.orgId,
|
|
25338
|
-
factoryProjectId: request.factoryProjectId,
|
|
25339
|
-
workItemId: prepared.item.id,
|
|
25340
|
-
board: prepared.item.externalSource?.type === "pull-request" ? "review" : "work",
|
|
25341
|
-
stage: request.destinationStage,
|
|
25342
|
-
expectedRevision: prepared.item.revision,
|
|
25343
|
-
actor: { type: "human", id: request.userId },
|
|
25344
|
-
ingress: { type: "human", identity: `start:${request.kickoffKey}:transition` },
|
|
25345
|
-
cause: "run_start"
|
|
25346
|
-
});
|
|
25347
|
-
if (transition.status === "rejected") {
|
|
25348
|
-
await storage.markPendingStart(prepared.binding.id, "failed", transition.reason);
|
|
25349
|
-
throw new FactoryStartTransitionError(transition);
|
|
25350
|
-
}
|
|
25351
|
-
revision = transition.revision;
|
|
25352
|
-
}
|
|
25353
|
-
if (kickoffMessage === null) {
|
|
25354
|
-
await storage.markPendingStart(prepared.binding.id, "sent");
|
|
25355
|
-
prepared.pendingStart.status = "sent";
|
|
25356
|
-
}
|
|
25357
|
-
return {
|
|
25358
|
-
workItemId: prepared.item.id,
|
|
25359
|
-
bindingId: prepared.binding.id,
|
|
25360
|
-
threadId,
|
|
25361
|
-
resourceId: sourceSession.sessionId,
|
|
25362
|
-
sessionId: sourceSession.sessionId,
|
|
25363
|
-
branch: sourceSession.branch,
|
|
25364
|
-
revision,
|
|
25365
|
-
kickoffStatus: prepared.pendingStart.status,
|
|
25366
|
-
replayed: prepared.replayed
|
|
25367
|
-
};
|
|
25368
|
-
}
|
|
25369
|
-
};
|
|
25370
|
-
|
|
25371
25045
|
// src/rules/transition-service.ts
|
|
25372
|
-
|
|
25373
|
-
var RULE_TIMEOUT_MS3 = 5e3;
|
|
25046
|
+
var RULE_TIMEOUT_MS = 5e3;
|
|
25374
25047
|
var MAX_REJECTION_REASON = 512;
|
|
25375
25048
|
function rejection(transitionId, itemId, code, reason) {
|
|
25376
25049
|
return { status: "rejected", transitionId, itemId, code, reason: reason.slice(0, MAX_REJECTION_REASON) };
|
|
@@ -25391,7 +25064,7 @@ function currentStage(stages) {
|
|
|
25391
25064
|
const stage = stages[0];
|
|
25392
25065
|
return FACTORY_RULE_STAGES.includes(stage) ? stage : void 0;
|
|
25393
25066
|
}
|
|
25394
|
-
function
|
|
25067
|
+
function workItemSource(source) {
|
|
25395
25068
|
if (!source) return "manual";
|
|
25396
25069
|
if (source.integrationId === "linear") return "linear-issue";
|
|
25397
25070
|
return source.type === "pull-request" ? "github-pr" : "github-issue";
|
|
@@ -25411,7 +25084,7 @@ function ruleFailure(error) {
|
|
|
25411
25084
|
reason: error instanceof Error ? `Factory rule failed: ${error.message}` : "Factory rule failed."
|
|
25412
25085
|
};
|
|
25413
25086
|
}
|
|
25414
|
-
async function
|
|
25087
|
+
async function withRuleTimeout(operation, timeoutMs) {
|
|
25415
25088
|
let timer;
|
|
25416
25089
|
const timeout = new Promise((_, reject) => {
|
|
25417
25090
|
timer = setTimeout(() => reject(new Error("FACTORY_RULE_TIMEOUT")), timeoutMs);
|
|
@@ -25429,7 +25102,7 @@ var FactoryTransitionService = class {
|
|
|
25429
25102
|
constructor(options) {
|
|
25430
25103
|
this.#rules = options.rules;
|
|
25431
25104
|
this.#storage = options.storage;
|
|
25432
|
-
this.#timeoutMs = options.timeoutMs ??
|
|
25105
|
+
this.#timeoutMs = options.timeoutMs ?? RULE_TIMEOUT_MS;
|
|
25433
25106
|
}
|
|
25434
25107
|
get ruleSetVersion() {
|
|
25435
25108
|
return this.#rules.version;
|
|
@@ -25454,7 +25127,7 @@ var FactoryTransitionService = class {
|
|
|
25454
25127
|
"Factory rule causal depth exceeded."
|
|
25455
25128
|
);
|
|
25456
25129
|
}
|
|
25457
|
-
const itemSource =
|
|
25130
|
+
const itemSource = workItemSource(item.externalSource);
|
|
25458
25131
|
const source = factoryRuleSourceForWorkItem(itemSource);
|
|
25459
25132
|
if (request.board === "review" !== (source === "pullRequest")) {
|
|
25460
25133
|
return this.#commitRejection(
|
|
@@ -25497,7 +25170,7 @@ var FactoryTransitionService = class {
|
|
|
25497
25170
|
};
|
|
25498
25171
|
let evaluation;
|
|
25499
25172
|
try {
|
|
25500
|
-
evaluation = await
|
|
25173
|
+
evaluation = await withRuleTimeout(
|
|
25501
25174
|
(async () => {
|
|
25502
25175
|
const decisions = [];
|
|
25503
25176
|
for (const rule of resolveFactoryStageRules(this.#rules, {
|
|
@@ -28816,6 +28489,7 @@ function buildIntegrationContext(deps, integrationId) {
|
|
|
28816
28489
|
projects: deps.domains.projects,
|
|
28817
28490
|
intake: deps.domains.intake
|
|
28818
28491
|
},
|
|
28492
|
+
...deps.factoryReady ? { rules: { config: deps.rules, workItems: deps.domains.workItems } } : {},
|
|
28819
28493
|
...deps.emitAudit ? { hooks: { emitAudit: deps.emitAudit } } : {}
|
|
28820
28494
|
};
|
|
28821
28495
|
}
|
|
@@ -28866,36 +28540,12 @@ function assembleFactoryApiRoutes(deps) {
|
|
|
28866
28540
|
const emitAudit = (args) => deps.audit.emit(args);
|
|
28867
28541
|
const registrations = deps.integrations ?? [];
|
|
28868
28542
|
const githubRegistration = registrations.find(({ integration }) => integration.id === "github");
|
|
28869
|
-
const linearRegistration = registrations.find(({ integration }) => integration.id === "linear");
|
|
28870
28543
|
const githubStorage = githubRegistration ? deps.sourceControlStorage.forIntegration("github") : void 0;
|
|
28871
28544
|
const githubIntegration = githubRegistration?.integration;
|
|
28872
|
-
const workItems = deps.factoryReady ? deps.domains.workItems : void 0;
|
|
28873
|
-
const githubEventService = githubIntegration && githubStorage && workItems ? new FactoryGithubEventService({
|
|
28874
|
-
github: githubIntegration,
|
|
28875
|
-
sourceControl: githubStorage,
|
|
28876
|
-
integrationStorage: deps.integrationStorage.forIntegration("github"),
|
|
28877
|
-
projects: deps.domains.projects,
|
|
28878
|
-
storage: workItems,
|
|
28879
|
-
rules: deps.rules
|
|
28880
|
-
}) : void 0;
|
|
28881
|
-
const linearIssueService = linearRegistration && workItems ? new FactoryLinearIssueService({
|
|
28882
|
-
projects: deps.domains.projects,
|
|
28883
|
-
storage: workItems,
|
|
28884
|
-
rules: deps.rules
|
|
28885
|
-
}) : void 0;
|
|
28886
28545
|
const integrationRoutes = registrations.flatMap((registration) => {
|
|
28887
28546
|
const { integration } = registration;
|
|
28888
28547
|
if (!deps.stateSigner) return disabledIntegrationStatusRoutes(deps, integration.id, true);
|
|
28889
28548
|
const context = buildIntegrationContext({ ...deps, stateSigner: deps.stateSigner, emitAudit }, integration.id);
|
|
28890
|
-
if (integration.id === "github") {
|
|
28891
|
-
context.hooks = {
|
|
28892
|
-
...context.hooks,
|
|
28893
|
-
...githubEventService ? { ingestGithubEvent: (event) => githubEventService.ingest(event) } : {}
|
|
28894
|
-
};
|
|
28895
|
-
}
|
|
28896
|
-
if (integration.id === "linear" && linearIssueService) {
|
|
28897
|
-
context.hooks = { ...context.hooks, ingestLinearIssues: (input) => linearIssueService.ingest(input) };
|
|
28898
|
-
}
|
|
28899
28549
|
return guardIntegrationRoutes({ ...registration, routes: integration.routes(context) });
|
|
28900
28550
|
});
|
|
28901
28551
|
const absentStubs = ["github", "linear"].filter((id) => !registrations.some(({ integration }) => integration.id === id)).flatMap((id) => disabledIntegrationStatusRoutes(deps, id));
|