@mastra/factory 0.1.0-alpha.2 → 0.1.0-alpha.4
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 +46 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +812 -209
- package/dist/factory.js.map +1 -1
- package/dist/index.js +812 -209
- package/dist/index.js.map +1 -1
- package/dist/integrations/github/integration.d.ts +2 -2
- package/dist/integrations/github/integration.js +45 -11
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/provenance.js.map +1 -1
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +12 -9
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/sandbox.d.ts +1 -0
- package/dist/integrations/github/sandbox.d.ts.map +1 -1
- package/dist/integrations/github/sandbox.js +2 -2
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/github/session-subscriptions.d.ts +3 -0
- package/dist/integrations/github/session-subscriptions.d.ts.map +1 -1
- package/dist/integrations/github/session-subscriptions.js +30 -0
- package/dist/integrations/github/session-subscriptions.js.map +1 -1
- package/dist/integrations/github/token-refresh.d.ts +6 -0
- package/dist/integrations/github/token-refresh.d.ts.map +1 -0
- package/dist/integrations/github/token-refresh.js +17 -0
- package/dist/integrations/github/token-refresh.js.map +1 -0
- 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 +8 -0
- 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 +52 -9
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/routes/config.d.ts +16 -11
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +222 -109
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/custom-provider-source.d.ts +52 -0
- package/dist/routes/custom-provider-source.d.ts.map +1 -0
- package/dist/routes/custom-provider-source.js +107 -0
- package/dist/routes/custom-provider-source.js.map +1 -0
- package/dist/routes/oauth.js +33 -1
- package/dist/routes/oauth.js.map +1 -1
- package/dist/routes/surface.d.ts +4 -0
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +282 -111
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/defaults.d.ts.map +1 -1
- package/dist/rules/defaults.js +8 -2
- package/dist/rules/defaults.js.map +1 -1
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/github-service.d.ts +2 -0
- package/dist/rules/github-service.d.ts.map +1 -1
- package/dist/rules/github-service.js +15 -1
- package/dist/rules/github-service.js.map +1 -1
- package/dist/rules/index.js +8 -2
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/linear-service.js.map +1 -1
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/tools.js.map +1 -1
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.d.ts +5 -0
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/types.js.map +1 -1
- package/dist/rules/validation.js.map +1 -1
- package/dist/sandbox/fleet.d.ts +3 -0
- package/dist/sandbox/fleet.d.ts.map +1 -1
- package/dist/sandbox/fleet.js +10 -3
- package/dist/sandbox/fleet.js.map +1 -1
- package/dist/spa-static.d.ts +4 -5
- package/dist/spa-static.d.ts.map +1 -1
- package/dist/spa-static.js +5 -2
- package/dist/spa-static.js.map +1 -1
- package/dist/storage/domains/custom-providers/base.d.ts +57 -0
- package/dist/storage/domains/custom-providers/base.d.ts.map +1 -0
- package/dist/storage/domains/custom-providers/base.js +150 -0
- package/dist/storage/domains/custom-providers/base.js.map +1 -0
- package/dist/storage/domains/memory-settings/base.d.ts +62 -0
- package/dist/storage/domains/memory-settings/base.d.ts.map +1 -0
- package/dist/storage/domains/memory-settings/base.js +111 -0
- package/dist/storage/domains/memory-settings/base.js.map +1 -0
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +17 -0
- package/dist/workspace.js.map +1 -1
- package/package.json +7 -6
package/dist/factory.js
CHANGED
|
@@ -11163,8 +11163,10 @@ function assertIdentifier(kind, name) {
|
|
|
11163
11163
|
}
|
|
11164
11164
|
}
|
|
11165
11165
|
function isUniqueViolation(error) {
|
|
11166
|
+
const code = typeof error === "object" && error !== null ? error.code : void 0;
|
|
11167
|
+
if (code === "SQLITE_CONSTRAINT_UNIQUE" || code === "SQLITE_CONSTRAINT_PRIMARYKEY") return true;
|
|
11166
11168
|
const message = error instanceof Error ? error.message : String(error);
|
|
11167
|
-
return message.includes("UNIQUE constraint failed") || message.includes("
|
|
11169
|
+
return message.includes("UNIQUE constraint failed") || message.includes("SQLITE_CONSTRAINT_UNIQUE") || message.includes("SQLITE_CONSTRAINT_PRIMARYKEY");
|
|
11168
11170
|
}
|
|
11169
11171
|
function primaryKeyOf(schema) {
|
|
11170
11172
|
const pks = Object.entries(schema.columns).filter(([, spec]) => spec.type === "uuid-pk" || spec.primaryKey);
|
|
@@ -24103,6 +24105,35 @@ ${unreflectedContent}` : bufferedReflection;
|
|
|
24103
24105
|
if (spec.default !== void 0) ddl += ` DEFAULT ${serializeDefault(spec.default)}`;
|
|
24104
24106
|
return ddl;
|
|
24105
24107
|
}
|
|
24108
|
+
/**
|
|
24109
|
+
* A table created by an older schema may still say NOT NULL on a column the
|
|
24110
|
+
* current schema declares nullable — inserts of null then fail on databases
|
|
24111
|
+
* that predate the change. SQLite has no `ALTER COLUMN DROP NOT NULL`, so
|
|
24112
|
+
* relaxation swaps in a table rebuilt from the current schema (create shadow
|
|
24113
|
+
* → copy → drop → rename) atomically.
|
|
24114
|
+
*/
|
|
24115
|
+
async #relaxDriftedNotNulls(schema) {
|
|
24116
|
+
const info = await this.#client.execute(`PRAGMA table_info("${schema.name}")`);
|
|
24117
|
+
const hasDrift = info.rows.some((row) => {
|
|
24118
|
+
const spec = schema.columns[String(row.name)];
|
|
24119
|
+
if (!spec || spec.type === "uuid-pk" || spec.primaryKey) return false;
|
|
24120
|
+
return spec.nullable === true && Number(row.notnull) === 1;
|
|
24121
|
+
});
|
|
24122
|
+
if (!hasDrift) return;
|
|
24123
|
+
const ddl = Object.entries(schema.columns).map(([name, spec]) => this.#columnDdl(name, spec));
|
|
24124
|
+
const shadow = `${schema.name}__nullable_rebuild`;
|
|
24125
|
+
const cols = Object.keys(schema.columns).map((name) => `"${name}"`).join(", ");
|
|
24126
|
+
await this.#client.batch(
|
|
24127
|
+
[
|
|
24128
|
+
`DROP TABLE IF EXISTS "${shadow}"`,
|
|
24129
|
+
`CREATE TABLE "${shadow}" (${ddl.join(", ")})`,
|
|
24130
|
+
`INSERT INTO "${shadow}" (${cols}) SELECT ${cols} FROM "${schema.name}"`,
|
|
24131
|
+
`DROP TABLE "${schema.name}"`,
|
|
24132
|
+
`ALTER TABLE "${shadow}" RENAME TO "${schema.name}"`
|
|
24133
|
+
],
|
|
24134
|
+
"write"
|
|
24135
|
+
);
|
|
24136
|
+
}
|
|
24106
24137
|
async #ensureCollection(schema) {
|
|
24107
24138
|
assertIdentifier("collection", schema.name);
|
|
24108
24139
|
primaryKeyOf(schema);
|
|
@@ -24114,6 +24145,7 @@ ${unreflectedContent}` : bufferedReflection;
|
|
|
24114
24145
|
if (existing.has(name)) continue;
|
|
24115
24146
|
await this.#client.execute(`ALTER TABLE "${schema.name}" ADD COLUMN ${this.#columnDdl(name, spec)}`);
|
|
24116
24147
|
}
|
|
24148
|
+
await this.#relaxDriftedNotNulls(schema);
|
|
24117
24149
|
for (const index of schema.uniqueIndexes ?? []) {
|
|
24118
24150
|
assertIdentifier("index", index.name);
|
|
24119
24151
|
index.columns.forEach((column) => assertIdentifier("column", column));
|
|
@@ -24798,6 +24830,19 @@ function retirePullRequestSubscription(id, status, storage) {
|
|
|
24798
24830
|
return storage.subscriptions.updateStatus(id, status);
|
|
24799
24831
|
}
|
|
24800
24832
|
|
|
24833
|
+
// src/integrations/github/token-refresh.ts
|
|
24834
|
+
var GITHUB_TOKEN_INJECTOR_CONTEXT_KEY = "factoryGithubTokenInjector";
|
|
24835
|
+
function registerGithubTokenInjector(requestContext, injector) {
|
|
24836
|
+
requestContext.set(GITHUB_TOKEN_INJECTOR_CONTEXT_KEY, injector);
|
|
24837
|
+
}
|
|
24838
|
+
function injectGithubToken(requestContext, token) {
|
|
24839
|
+
const injector = requestContext.get(GITHUB_TOKEN_INJECTOR_CONTEXT_KEY);
|
|
24840
|
+
if (!injector) {
|
|
24841
|
+
throw new Error("GitHub token refresh requires an active Factory sandbox workspace.");
|
|
24842
|
+
}
|
|
24843
|
+
injector(token);
|
|
24844
|
+
}
|
|
24845
|
+
|
|
24801
24846
|
// src/integrations/github/session-subscriptions.ts
|
|
24802
24847
|
function sessionUserId(user) {
|
|
24803
24848
|
return user?.workosId ?? user?.id;
|
|
@@ -24885,11 +24930,30 @@ async function unsubscribeCurrentSessionFromPullRequest(requestContext, pullRequ
|
|
|
24885
24930
|
await unsubscribeFromPullRequest(await subscriptionInput(target, number3), github.integrationStorage);
|
|
24886
24931
|
return number3;
|
|
24887
24932
|
}
|
|
24933
|
+
async function refreshGithubToken(requestContext, github) {
|
|
24934
|
+
const target = await resolveSessionTarget(requestContext, github);
|
|
24935
|
+
const access = await github.versionControl.getRepositoryAccess({
|
|
24936
|
+
orgId: target.orgId,
|
|
24937
|
+
repositoryId: target.repository.id
|
|
24938
|
+
});
|
|
24939
|
+
const token = access.authorization?.token;
|
|
24940
|
+
if (!token) throw new Error("Repository access did not include a bearer token for the Factory session.");
|
|
24941
|
+
injectGithubToken(requestContext, token);
|
|
24942
|
+
}
|
|
24888
24943
|
function createGithubSubscriptionTools(requestContext, github) {
|
|
24889
24944
|
const context = requestContext.get("controller");
|
|
24890
24945
|
const user = requestContext.get("user");
|
|
24891
24946
|
if (!context?.getState().projectRepositoryId || !sessionOrgId(user) || !sessionUserId(user)) return {};
|
|
24892
24947
|
return {
|
|
24948
|
+
github_refresh_token: createTool({
|
|
24949
|
+
id: "github_refresh_token",
|
|
24950
|
+
description: "Refresh GitHub CLI authentication in the active Factory sandbox. Use this after a gh command fails because authentication is expired, invalid, or missing. It installs a fresh GH_TOKEN for subsequent sandbox commands. After this tool succeeds, retry the failed gh command. Takes no arguments and never returns the token.",
|
|
24951
|
+
inputSchema: z.object({}),
|
|
24952
|
+
execute: async () => {
|
|
24953
|
+
await refreshGithubToken(requestContext, github);
|
|
24954
|
+
return { refreshed: true };
|
|
24955
|
+
}
|
|
24956
|
+
}),
|
|
24893
24957
|
github_subscribe_pr: createTool({
|
|
24894
24958
|
id: "github_subscribe_pr",
|
|
24895
24959
|
description: "Subscribe this thread to GitHub pull request activity. You usually do not need this tool: successful gh pr create commands subscribe automatically. Use it for an existing PR or to recover when automatic subscription did not occur. Closed or merged PRs are unsubscribed automatically. Accepts a PR number or canonical URL for the active project.",
|
|
@@ -25033,20 +25097,27 @@ var SandboxBudgetError = class extends Error {
|
|
|
25033
25097
|
max;
|
|
25034
25098
|
code = "sandbox-budget-exceeded";
|
|
25035
25099
|
};
|
|
25036
|
-
function toMaterializationSandbox(sandbox) {
|
|
25100
|
+
function toMaterializationSandbox(sandbox, initialEnvironment = {}) {
|
|
25037
25101
|
if (typeof sandbox.executeCommand !== "function") {
|
|
25038
25102
|
throw new Error(
|
|
25039
25103
|
`Sandbox provider '${sandbox.provider}' does not implement executeCommand() \u2014 cannot materialize repos.`
|
|
25040
25104
|
);
|
|
25041
25105
|
}
|
|
25042
25106
|
const lifecycle = sandbox;
|
|
25107
|
+
const environment = { ...initialEnvironment };
|
|
25043
25108
|
return {
|
|
25044
25109
|
id: sandbox.id,
|
|
25045
25110
|
start: async () => {
|
|
25046
25111
|
await (lifecycle._start ?? sandbox.start)?.call(sandbox);
|
|
25047
25112
|
},
|
|
25048
25113
|
getInfo: async () => await sandbox.getInfo?.() ?? {},
|
|
25049
|
-
executeCommand: (command, args, options) => sandbox.executeCommand(command, args,
|
|
25114
|
+
executeCommand: (command, args, options) => sandbox.executeCommand(command, args, {
|
|
25115
|
+
...options,
|
|
25116
|
+
env: { ...environment, ...options?.env }
|
|
25117
|
+
}),
|
|
25118
|
+
setEnvironmentVariable: (name, value) => {
|
|
25119
|
+
environment[name] = value;
|
|
25120
|
+
},
|
|
25050
25121
|
stop: async () => {
|
|
25051
25122
|
await (lifecycle._stop ?? sandbox.stop)?.call(sandbox);
|
|
25052
25123
|
}
|
|
@@ -25186,7 +25257,7 @@ var SandboxFleet = class {
|
|
|
25186
25257
|
...opts.idleTimeoutMinutes !== void 0 ? { idleTimeoutMinutes: opts.idleTimeoutMinutes } : {},
|
|
25187
25258
|
...opts.checkpointName ? { checkpointName: opts.checkpointName } : {}
|
|
25188
25259
|
});
|
|
25189
|
-
return toMaterializationSandbox(clone);
|
|
25260
|
+
return toMaterializationSandbox(clone, opts.env);
|
|
25190
25261
|
}
|
|
25191
25262
|
async ensureSandbox(store, envOrProgress, progressOrOptions, maybeOptions = {}) {
|
|
25192
25263
|
const env = typeof envOrProgress === "function" ? void 0 : envOrProgress;
|
|
@@ -25356,8 +25427,8 @@ function bindingStore(row, storage) {
|
|
|
25356
25427
|
};
|
|
25357
25428
|
}
|
|
25358
25429
|
async function ensureProjectSandbox(options) {
|
|
25359
|
-
const { fleet, row, storage, onProgress } = options;
|
|
25360
|
-
return fleet.ensureSandbox(bindingStore(row, storage), onProgress);
|
|
25430
|
+
const { fleet, row, storage, token, onProgress } = options;
|
|
25431
|
+
return fleet.ensureSandbox(bindingStore(row, storage), { GH_TOKEN: token }, onProgress);
|
|
25361
25432
|
}
|
|
25362
25433
|
async function teardownProjectSandbox(options) {
|
|
25363
25434
|
const { fleet, row, storage, sandbox } = options;
|
|
@@ -26073,6 +26144,7 @@ function polledIssueEvent(project, issue) {
|
|
|
26073
26144
|
number: issue.number,
|
|
26074
26145
|
title: issue.title,
|
|
26075
26146
|
html_url: issue.url,
|
|
26147
|
+
created_at: issue.createdAt,
|
|
26076
26148
|
labels: issue.labels.map((name) => ({ name }))
|
|
26077
26149
|
}
|
|
26078
26150
|
}
|
|
@@ -26092,6 +26164,7 @@ function polledPullRequestEvent(project, pullRequest) {
|
|
|
26092
26164
|
number: pullRequest.number,
|
|
26093
26165
|
title: pullRequest.title,
|
|
26094
26166
|
html_url: pullRequest.url,
|
|
26167
|
+
created_at: pullRequest.createdAt,
|
|
26095
26168
|
state: "open",
|
|
26096
26169
|
merged: false,
|
|
26097
26170
|
head: { ref: pullRequest.headBranch },
|
|
@@ -26621,13 +26694,6 @@ async function loadOrCreateSandboxRow(github, project, userId) {
|
|
|
26621
26694
|
async function prepareProject(options) {
|
|
26622
26695
|
const { github, fleet, project, userId, onProgress } = options;
|
|
26623
26696
|
const sandboxRow = await loadOrCreateSandboxRow(github, project, userId);
|
|
26624
|
-
const sandbox = await ensureProjectSandbox({
|
|
26625
|
-
fleet,
|
|
26626
|
-
row: sandboxRow,
|
|
26627
|
-
storage: github.sourceControlStorage.sandboxes,
|
|
26628
|
-
onProgress
|
|
26629
|
-
});
|
|
26630
|
-
const fresh = await github.sourceControlStorage.sandboxes.getById({ id: sandboxRow.id });
|
|
26631
26697
|
const access = await github.versionControl.getRepositoryAccess({
|
|
26632
26698
|
orgId: project.installation.orgId,
|
|
26633
26699
|
repositoryId: project.repository.id
|
|
@@ -26635,6 +26701,14 @@ async function prepareProject(options) {
|
|
|
26635
26701
|
if (!access.authorization) {
|
|
26636
26702
|
throw new MaterializeError("Repository access did not include a bearer token.", "clone-failed");
|
|
26637
26703
|
}
|
|
26704
|
+
const sandbox = await ensureProjectSandbox({
|
|
26705
|
+
fleet,
|
|
26706
|
+
row: sandboxRow,
|
|
26707
|
+
storage: github.sourceControlStorage.sandboxes,
|
|
26708
|
+
token: access.authorization.token,
|
|
26709
|
+
onProgress
|
|
26710
|
+
});
|
|
26711
|
+
const fresh = await github.sourceControlStorage.sandboxes.getById({ id: sandboxRow.id });
|
|
26638
26712
|
const finalRow = fresh ?? sandboxRow;
|
|
26639
26713
|
await materializeRepo({
|
|
26640
26714
|
row: finalRow,
|
|
@@ -27240,6 +27314,7 @@ var PlatformGithubEventWorker = class extends MastraWorker {
|
|
|
27240
27314
|
#controller;
|
|
27241
27315
|
#github;
|
|
27242
27316
|
#storage;
|
|
27317
|
+
#ingestFactoryEvent;
|
|
27243
27318
|
#intervalMs;
|
|
27244
27319
|
#now;
|
|
27245
27320
|
#dispatch;
|
|
@@ -27259,6 +27334,7 @@ var PlatformGithubEventWorker = class extends MastraWorker {
|
|
|
27259
27334
|
this.#controller = config.controller;
|
|
27260
27335
|
this.#github = config.github;
|
|
27261
27336
|
this.#storage = config.storage;
|
|
27337
|
+
this.#ingestFactoryEvent = config.ingestFactoryEvent;
|
|
27262
27338
|
this.#intervalMs = config.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
27263
27339
|
if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {
|
|
27264
27340
|
throw new Error("Platform GitHub event polling interval must be a positive number.");
|
|
@@ -27416,6 +27492,9 @@ var PlatformGithubEventWorker = class extends MastraWorker {
|
|
|
27416
27492
|
});
|
|
27417
27493
|
continue;
|
|
27418
27494
|
}
|
|
27495
|
+
if (isFactoryClosureEvent(parsed)) {
|
|
27496
|
+
await this.#ingestFactoryEvent?.(parsed);
|
|
27497
|
+
}
|
|
27419
27498
|
const result = await this.#dispatch(parsed, {
|
|
27420
27499
|
controller: this.#controller,
|
|
27421
27500
|
listSubscriptions: (target, options) => listPullRequestSubscriptionsForWebhook(target, options, this.#github.integrationStorage),
|
|
@@ -27481,6 +27560,9 @@ function normalizeSettings(value) {
|
|
|
27481
27560
|
}
|
|
27482
27561
|
return { version: 1, repositories: { ...value.repositories } };
|
|
27483
27562
|
}
|
|
27563
|
+
function isFactoryClosureEvent(event) {
|
|
27564
|
+
return (event.event === "issues" || event.event === "pull_request") && event.payload.action === "closed";
|
|
27565
|
+
}
|
|
27484
27566
|
function parseEvent(event) {
|
|
27485
27567
|
if (!event.id || !event.deliveryId || !SUPPORTED_EVENTS.has(event.event) || !event.payload || typeof event.payload !== "object" || Array.isArray(event.payload)) {
|
|
27486
27568
|
return null;
|
|
@@ -27829,6 +27911,7 @@ var PlatformGithubIntegration = class {
|
|
|
27829
27911
|
controller: ctx.controller,
|
|
27830
27912
|
github: this,
|
|
27831
27913
|
storage: ctx.storage.generic,
|
|
27914
|
+
ingestFactoryEvent: ctx.hooks?.ingestGithubEvent,
|
|
27832
27915
|
intervalMs: this.#pollingIntervalMs
|
|
27833
27916
|
})
|
|
27834
27917
|
];
|
|
@@ -29065,6 +29148,158 @@ function isNotFound2(error) {
|
|
|
29065
29148
|
return error instanceof PlatformApiError && error.status === 404;
|
|
29066
29149
|
}
|
|
29067
29150
|
|
|
29151
|
+
// src/routes/custom-provider-source.ts
|
|
29152
|
+
import { setCustomProvidersSource } from "@mastra/code-sdk/agents/custom-provider-source";
|
|
29153
|
+
|
|
29154
|
+
// src/routes/provider-credentials.ts
|
|
29155
|
+
function getAuthProviderId(provider) {
|
|
29156
|
+
return provider === "openai" ? "openai-codex" : provider;
|
|
29157
|
+
}
|
|
29158
|
+
var WEB_OAUTH_FLOW_KINDS = {
|
|
29159
|
+
anthropic: "paste-code",
|
|
29160
|
+
openai: "device-code",
|
|
29161
|
+
"github-copilot": "device-code",
|
|
29162
|
+
xai: "device-code"
|
|
29163
|
+
};
|
|
29164
|
+
async function getTenantCredentialsStorage(credentials) {
|
|
29165
|
+
if (!credentials) return void 0;
|
|
29166
|
+
try {
|
|
29167
|
+
await credentials.ensureReady();
|
|
29168
|
+
} catch {
|
|
29169
|
+
return void 0;
|
|
29170
|
+
}
|
|
29171
|
+
return credentials;
|
|
29172
|
+
}
|
|
29173
|
+
function tenantOrgId(tenant) {
|
|
29174
|
+
return tenant.orgId ?? `user:${tenant.userId}`;
|
|
29175
|
+
}
|
|
29176
|
+
async function resolveCredentialContext({
|
|
29177
|
+
c,
|
|
29178
|
+
auth,
|
|
29179
|
+
credentials
|
|
29180
|
+
}) {
|
|
29181
|
+
await auth.ensureUser(c);
|
|
29182
|
+
const tenant = auth.tenant(c);
|
|
29183
|
+
if (!tenant) {
|
|
29184
|
+
if (auth.enabled()) return { response: c.json({ error: "unauthorized" }, 401) };
|
|
29185
|
+
return { mode: "local" };
|
|
29186
|
+
}
|
|
29187
|
+
const storage = await getTenantCredentialsStorage(credentials);
|
|
29188
|
+
if (!storage) {
|
|
29189
|
+
return {
|
|
29190
|
+
response: c.json(
|
|
29191
|
+
{
|
|
29192
|
+
error: "credentials_unavailable",
|
|
29193
|
+
message: "Tenant credential storage is unavailable \u2014 the app database is not configured or failed to start."
|
|
29194
|
+
},
|
|
29195
|
+
503
|
|
29196
|
+
)
|
|
29197
|
+
};
|
|
29198
|
+
}
|
|
29199
|
+
return { mode: "tenant", storage, orgId: tenantOrgId(tenant), userId: tenant.userId };
|
|
29200
|
+
}
|
|
29201
|
+
async function listTenantCredentialsForRequest({
|
|
29202
|
+
c,
|
|
29203
|
+
auth,
|
|
29204
|
+
credentials
|
|
29205
|
+
}) {
|
|
29206
|
+
await auth.ensureUser(c);
|
|
29207
|
+
const tenant = auth.tenant(c);
|
|
29208
|
+
if (!tenant) return auth.enabled() ? [] : void 0;
|
|
29209
|
+
const storage = await getTenantCredentialsStorage(credentials);
|
|
29210
|
+
if (!storage) return [];
|
|
29211
|
+
return storage.listCredentials(tenantOrgId(tenant), tenant.userId);
|
|
29212
|
+
}
|
|
29213
|
+
|
|
29214
|
+
// src/routes/custom-provider-source.ts
|
|
29215
|
+
var SNAPSHOT_TTL_MS = 15e3;
|
|
29216
|
+
var MAX_CACHED_ORGS = 1e3;
|
|
29217
|
+
var LOCAL_ORG = "local";
|
|
29218
|
+
var OrgCustomProvidersSnapshot = class {
|
|
29219
|
+
#orgId;
|
|
29220
|
+
#storage;
|
|
29221
|
+
#snapshot = [];
|
|
29222
|
+
#fetchedAt = 0;
|
|
29223
|
+
#hydrating;
|
|
29224
|
+
constructor(orgId, storage) {
|
|
29225
|
+
this.#orgId = orgId;
|
|
29226
|
+
this.#storage = storage;
|
|
29227
|
+
}
|
|
29228
|
+
/** Hydrate the snapshot when stale; coalesces concurrent callers. */
|
|
29229
|
+
async ensureFresh(now = Date.now()) {
|
|
29230
|
+
if (now - this.#fetchedAt < SNAPSHOT_TTL_MS) return;
|
|
29231
|
+
this.#hydrating ??= this.#hydrate().finally(() => {
|
|
29232
|
+
this.#hydrating = void 0;
|
|
29233
|
+
});
|
|
29234
|
+
await this.#hydrating;
|
|
29235
|
+
}
|
|
29236
|
+
async #hydrate() {
|
|
29237
|
+
await this.#storage.ensureReady();
|
|
29238
|
+
const records = await this.#storage.list({ orgId: this.#orgId });
|
|
29239
|
+
this.#snapshot = records.map((record) => ({
|
|
29240
|
+
name: record.name,
|
|
29241
|
+
url: record.url,
|
|
29242
|
+
apiKey: record.apiKey ?? void 0,
|
|
29243
|
+
models: record.models
|
|
29244
|
+
}));
|
|
29245
|
+
this.#fetchedAt = Date.now();
|
|
29246
|
+
}
|
|
29247
|
+
/** Sync by contract; kicks a background re-hydrate when the snapshot is stale. */
|
|
29248
|
+
get() {
|
|
29249
|
+
if (Date.now() - this.#fetchedAt >= SNAPSHOT_TTL_MS) {
|
|
29250
|
+
void this.ensureFresh().catch(() => {
|
|
29251
|
+
});
|
|
29252
|
+
}
|
|
29253
|
+
return this.#snapshot;
|
|
29254
|
+
}
|
|
29255
|
+
};
|
|
29256
|
+
var orgSnapshots = /* @__PURE__ */ new Map();
|
|
29257
|
+
function snapshotFor(orgId, storage) {
|
|
29258
|
+
let snapshot = orgSnapshots.get(orgId);
|
|
29259
|
+
if (!snapshot) {
|
|
29260
|
+
if (orgSnapshots.size >= MAX_CACHED_ORGS) {
|
|
29261
|
+
const oldest = orgSnapshots.keys().next().value;
|
|
29262
|
+
if (oldest !== void 0) orgSnapshots.delete(oldest);
|
|
29263
|
+
}
|
|
29264
|
+
snapshot = new OrgCustomProvidersSnapshot(orgId, storage);
|
|
29265
|
+
orgSnapshots.set(orgId, snapshot);
|
|
29266
|
+
}
|
|
29267
|
+
return snapshot;
|
|
29268
|
+
}
|
|
29269
|
+
function orgForTenant(tenant, authEnabled) {
|
|
29270
|
+
if (!authEnabled) return LOCAL_ORG;
|
|
29271
|
+
return tenant ? tenantOrgId(tenant) : void 0;
|
|
29272
|
+
}
|
|
29273
|
+
function registerCustomProvidersSource({
|
|
29274
|
+
storage,
|
|
29275
|
+
authEnabled
|
|
29276
|
+
}) {
|
|
29277
|
+
setCustomProvidersSource((tenant) => {
|
|
29278
|
+
const orgId = orgForTenant(tenant, authEnabled);
|
|
29279
|
+
if (!orgId) return [];
|
|
29280
|
+
return snapshotFor(orgId, storage).get();
|
|
29281
|
+
});
|
|
29282
|
+
}
|
|
29283
|
+
function invalidateCustomProvidersSnapshots(tenant) {
|
|
29284
|
+
orgSnapshots.delete(tenant.orgId);
|
|
29285
|
+
}
|
|
29286
|
+
function createCustomProvidersPrimer({
|
|
29287
|
+
auth,
|
|
29288
|
+
storage,
|
|
29289
|
+
authEnabled
|
|
29290
|
+
}) {
|
|
29291
|
+
return async (c, next) => {
|
|
29292
|
+
const orgId = orgForTenant(auth.tenant(c), authEnabled);
|
|
29293
|
+
if (orgId) {
|
|
29294
|
+
try {
|
|
29295
|
+
await snapshotFor(orgId, storage).ensureFresh();
|
|
29296
|
+
} catch {
|
|
29297
|
+
}
|
|
29298
|
+
}
|
|
29299
|
+
await next();
|
|
29300
|
+
};
|
|
29301
|
+
}
|
|
29302
|
+
|
|
29068
29303
|
// src/routes/projects.ts
|
|
29069
29304
|
import { registerApiRoute as registerApiRoute6 } from "@mastra/core/server";
|
|
29070
29305
|
|
|
@@ -29931,6 +30166,11 @@ var FactoryGithubEventService = class {
|
|
|
29931
30166
|
return results[0] ?? { status: "ignored" };
|
|
29932
30167
|
}
|
|
29933
30168
|
async #ingestProject(parsed, event, installationId, repositoryId, repositoryName, login, project) {
|
|
30169
|
+
const factoryProject = await this.options.projects.get({
|
|
30170
|
+
orgId: project.orgId,
|
|
30171
|
+
id: project.factoryProjectId
|
|
30172
|
+
});
|
|
30173
|
+
if (!factoryProject) return { status: "missing" };
|
|
29934
30174
|
const issue = object(parsed.payload.issue);
|
|
29935
30175
|
const pullRequest = object(parsed.payload.pull_request);
|
|
29936
30176
|
const issueNumber = number(issue?.number);
|
|
@@ -29975,13 +30215,22 @@ var FactoryGithubEventService = class {
|
|
|
29975
30215
|
} : {},
|
|
29976
30216
|
event,
|
|
29977
30217
|
deliveryId: parsed.deliveryId,
|
|
30218
|
+
factory: { createdAt: factoryProject.createdAt.toISOString() },
|
|
29978
30219
|
repository: { id: repositoryId, fullName: repositoryName },
|
|
29979
|
-
...issueNumber && string(issue?.title) && string(issue?.html_url) ? {
|
|
30220
|
+
...issueNumber && string(issue?.title) && string(issue?.html_url) ? {
|
|
30221
|
+
issue: {
|
|
30222
|
+
number: issueNumber,
|
|
30223
|
+
title: string(issue?.title),
|
|
30224
|
+
url: string(issue?.html_url),
|
|
30225
|
+
...string(issue?.created_at) ? { createdAt: string(issue?.created_at) } : {}
|
|
30226
|
+
}
|
|
30227
|
+
} : {},
|
|
29980
30228
|
...pullRequestNumber && string(pullRequest?.title) && string(pullRequest?.html_url) ? {
|
|
29981
30229
|
pullRequest: {
|
|
29982
30230
|
number: pullRequestNumber,
|
|
29983
30231
|
title: string(pullRequest?.title),
|
|
29984
30232
|
url: string(pullRequest?.html_url),
|
|
30233
|
+
...string(pullRequest?.created_at) ? { createdAt: string(pullRequest?.created_at) } : {},
|
|
29985
30234
|
state: string(pullRequest?.state) === "closed" ? "closed" : "open",
|
|
29986
30235
|
merged: boolean(pullRequest?.merged) ?? false,
|
|
29987
30236
|
headBranch: string(object(pullRequest?.head)?.ref) ?? "",
|
|
@@ -30478,82 +30727,10 @@ var FactoryTransitionService = class {
|
|
|
30478
30727
|
};
|
|
30479
30728
|
|
|
30480
30729
|
// src/routes/config.ts
|
|
30481
|
-
import {
|
|
30482
|
-
import {
|
|
30483
|
-
removeCustomProviderFromSettings,
|
|
30484
|
-
upsertCustomProviderInSettings
|
|
30485
|
-
} from "@mastra/code-sdk/onboarding/custom-providers";
|
|
30486
|
-
import { applyOmRoleOverride, persistOmObserveAttachments } from "@mastra/code-sdk/onboarding/om-settings";
|
|
30730
|
+
import { DEFAULT_OM_MODEL_ID } from "@mastra/code-sdk/constants";
|
|
30487
30731
|
import { getAvailableModePacks } from "@mastra/code-sdk/onboarding/packs";
|
|
30488
|
-
import {
|
|
30489
|
-
getCustomProviderId,
|
|
30490
|
-
loadSettings,
|
|
30491
|
-
saveSettings,
|
|
30492
|
-
THREAD_ACTIVE_MODEL_PACK_ID_KEY
|
|
30493
|
-
} from "@mastra/code-sdk/onboarding/settings";
|
|
30732
|
+
import { getCustomProviderId, THREAD_ACTIVE_MODEL_PACK_ID_KEY } from "@mastra/code-sdk/onboarding/settings";
|
|
30494
30733
|
import { registerApiRoute as registerApiRoute7 } from "@mastra/core/server";
|
|
30495
|
-
|
|
30496
|
-
// src/routes/provider-credentials.ts
|
|
30497
|
-
function getAuthProviderId(provider) {
|
|
30498
|
-
return provider === "openai" ? "openai-codex" : provider;
|
|
30499
|
-
}
|
|
30500
|
-
var WEB_OAUTH_FLOW_KINDS = {
|
|
30501
|
-
anthropic: "paste-code",
|
|
30502
|
-
openai: "device-code",
|
|
30503
|
-
"github-copilot": "device-code",
|
|
30504
|
-
xai: "device-code"
|
|
30505
|
-
};
|
|
30506
|
-
async function getTenantCredentialsStorage(credentials) {
|
|
30507
|
-
if (!credentials) return void 0;
|
|
30508
|
-
try {
|
|
30509
|
-
await credentials.ensureReady();
|
|
30510
|
-
} catch {
|
|
30511
|
-
return void 0;
|
|
30512
|
-
}
|
|
30513
|
-
return credentials;
|
|
30514
|
-
}
|
|
30515
|
-
function tenantOrgId(tenant) {
|
|
30516
|
-
return tenant.orgId ?? `user:${tenant.userId}`;
|
|
30517
|
-
}
|
|
30518
|
-
async function resolveCredentialContext({
|
|
30519
|
-
c,
|
|
30520
|
-
auth,
|
|
30521
|
-
credentials
|
|
30522
|
-
}) {
|
|
30523
|
-
await auth.ensureUser(c);
|
|
30524
|
-
const tenant = auth.tenant(c);
|
|
30525
|
-
if (!tenant) {
|
|
30526
|
-
if (auth.enabled()) return { response: c.json({ error: "unauthorized" }, 401) };
|
|
30527
|
-
return { mode: "local" };
|
|
30528
|
-
}
|
|
30529
|
-
const storage = await getTenantCredentialsStorage(credentials);
|
|
30530
|
-
if (!storage) {
|
|
30531
|
-
return {
|
|
30532
|
-
response: c.json(
|
|
30533
|
-
{
|
|
30534
|
-
error: "credentials_unavailable",
|
|
30535
|
-
message: "Tenant credential storage is unavailable \u2014 the app database is not configured or failed to start."
|
|
30536
|
-
},
|
|
30537
|
-
503
|
|
30538
|
-
)
|
|
30539
|
-
};
|
|
30540
|
-
}
|
|
30541
|
-
return { mode: "tenant", storage, orgId: tenantOrgId(tenant), userId: tenant.userId };
|
|
30542
|
-
}
|
|
30543
|
-
async function listTenantCredentialsForRequest({
|
|
30544
|
-
c,
|
|
30545
|
-
auth,
|
|
30546
|
-
credentials
|
|
30547
|
-
}) {
|
|
30548
|
-
await auth.ensureUser(c);
|
|
30549
|
-
const tenant = auth.tenant(c);
|
|
30550
|
-
if (!tenant) return auth.enabled() ? [] : void 0;
|
|
30551
|
-
const storage = await getTenantCredentialsStorage(credentials);
|
|
30552
|
-
if (!storage) return [];
|
|
30553
|
-
return storage.listCredentials(tenantOrgId(tenant), tenant.userId);
|
|
30554
|
-
}
|
|
30555
|
-
|
|
30556
|
-
// src/routes/config.ts
|
|
30557
30734
|
function loose6(c) {
|
|
30558
30735
|
return c;
|
|
30559
30736
|
}
|
|
@@ -30597,15 +30774,39 @@ async function listProviders({
|
|
|
30597
30774
|
}
|
|
30598
30775
|
return Array.from(seen.values()).sort((a, b) => a.provider.localeCompare(b.provider));
|
|
30599
30776
|
}
|
|
30600
|
-
function
|
|
30601
|
-
|
|
30602
|
-
|
|
30603
|
-
|
|
30604
|
-
|
|
30605
|
-
|
|
30606
|
-
|
|
30607
|
-
|
|
30608
|
-
|
|
30777
|
+
function toCustomProviderInfo(record) {
|
|
30778
|
+
return {
|
|
30779
|
+
id: record.providerId,
|
|
30780
|
+
name: record.name,
|
|
30781
|
+
url: record.url,
|
|
30782
|
+
hasApiKey: Boolean(record.apiKey),
|
|
30783
|
+
models: record.models
|
|
30784
|
+
};
|
|
30785
|
+
}
|
|
30786
|
+
async function resolveCustomProvidersContext({
|
|
30787
|
+
c,
|
|
30788
|
+
auth,
|
|
30789
|
+
customProviders
|
|
30790
|
+
}) {
|
|
30791
|
+
await auth.ensureUser(c);
|
|
30792
|
+
const tenant = auth.tenant(c);
|
|
30793
|
+
if (!tenant && auth.enabled()) return { response: c.json({ error: "unauthorized" }, 401) };
|
|
30794
|
+
if (customProviders) {
|
|
30795
|
+
try {
|
|
30796
|
+
await customProviders.ensureReady();
|
|
30797
|
+
return tenant ? { storage: customProviders, orgId: tenantOrgId(tenant), userId: tenant.userId } : { storage: customProviders, orgId: "local", userId: "local" };
|
|
30798
|
+
} catch {
|
|
30799
|
+
}
|
|
30800
|
+
}
|
|
30801
|
+
return {
|
|
30802
|
+
response: c.json(
|
|
30803
|
+
{
|
|
30804
|
+
error: "custom_providers_unavailable",
|
|
30805
|
+
message: "Custom provider storage is unavailable \u2014 the app database is not configured or failed to start."
|
|
30806
|
+
},
|
|
30807
|
+
503
|
|
30808
|
+
)
|
|
30809
|
+
};
|
|
30609
30810
|
}
|
|
30610
30811
|
function parseCustomProviderBody(body) {
|
|
30611
30812
|
if (!body || typeof body !== "object") return { error: "Invalid JSON body" };
|
|
@@ -30670,15 +30871,6 @@ async function buildProviderAccess({
|
|
|
30670
30871
|
function canUseModelProvider(access, provider) {
|
|
30671
30872
|
return Boolean(access[provider]);
|
|
30672
30873
|
}
|
|
30673
|
-
async function getTenantModelPacksStorage(modelPacks) {
|
|
30674
|
-
if (!modelPacks) return void 0;
|
|
30675
|
-
try {
|
|
30676
|
-
await modelPacks.ensureReady();
|
|
30677
|
-
} catch {
|
|
30678
|
-
return void 0;
|
|
30679
|
-
}
|
|
30680
|
-
return modelPacks;
|
|
30681
|
-
}
|
|
30682
30874
|
async function resolvePackContext({
|
|
30683
30875
|
c,
|
|
30684
30876
|
auth,
|
|
@@ -30686,23 +30878,23 @@ async function resolvePackContext({
|
|
|
30686
30878
|
}) {
|
|
30687
30879
|
await auth.ensureUser(c);
|
|
30688
30880
|
const tenant = auth.tenant(c);
|
|
30689
|
-
if (!tenant) {
|
|
30690
|
-
|
|
30691
|
-
|
|
30692
|
-
|
|
30693
|
-
|
|
30694
|
-
|
|
30695
|
-
|
|
30696
|
-
response: c.json(
|
|
30697
|
-
{
|
|
30698
|
-
error: "model_packs_unavailable",
|
|
30699
|
-
message: "Model pack storage is unavailable \u2014 the app database is not configured or failed to start."
|
|
30700
|
-
},
|
|
30701
|
-
503
|
|
30702
|
-
)
|
|
30703
|
-
};
|
|
30881
|
+
if (!tenant && auth.enabled()) return { response: c.json({ error: "unauthorized" }, 401) };
|
|
30882
|
+
if (modelPacks) {
|
|
30883
|
+
try {
|
|
30884
|
+
await modelPacks.ensureReady();
|
|
30885
|
+
return tenant ? { storage: modelPacks, orgId: tenantOrgId(tenant), userId: tenant.userId } : { storage: modelPacks, orgId: "local", userId: "local" };
|
|
30886
|
+
} catch {
|
|
30887
|
+
}
|
|
30704
30888
|
}
|
|
30705
|
-
return {
|
|
30889
|
+
return {
|
|
30890
|
+
response: c.json(
|
|
30891
|
+
{
|
|
30892
|
+
error: "model_packs_unavailable",
|
|
30893
|
+
message: "Model pack storage is unavailable \u2014 the app database is not configured or failed to start."
|
|
30894
|
+
},
|
|
30895
|
+
503
|
|
30896
|
+
)
|
|
30897
|
+
};
|
|
30706
30898
|
}
|
|
30707
30899
|
function recordToModePack(record) {
|
|
30708
30900
|
return { id: `custom:${record.id}`, name: record.name, description: "Saved custom pack", models: record.models };
|
|
@@ -30715,7 +30907,7 @@ async function listModelPacks({
|
|
|
30715
30907
|
activePackId
|
|
30716
30908
|
}) {
|
|
30717
30909
|
const access = await buildProviderAccess({ controller, authStorage, tenantCredentials });
|
|
30718
|
-
const packs =
|
|
30910
|
+
const packs = [
|
|
30719
30911
|
...getAvailableModePacks(access),
|
|
30720
30912
|
...(await packContext.storage.list({ orgId: packContext.orgId })).map(recordToModePack)
|
|
30721
30913
|
];
|
|
@@ -30773,20 +30965,57 @@ function readOMConfig(session) {
|
|
|
30773
30965
|
observeAttachments: observeAttachments === true || observeAttachments === false ? observeAttachments : "auto"
|
|
30774
30966
|
};
|
|
30775
30967
|
}
|
|
30776
|
-
function
|
|
30777
|
-
|
|
30778
|
-
|
|
30779
|
-
|
|
30780
|
-
saveSettings(settings);
|
|
30781
|
-
}
|
|
30782
|
-
function persistOmRoleOverride({
|
|
30783
|
-
role,
|
|
30784
|
-
modelId,
|
|
30785
|
-
otherRoleCurrentModelId
|
|
30968
|
+
async function resolveMemorySettingsContext({
|
|
30969
|
+
c,
|
|
30970
|
+
auth,
|
|
30971
|
+
memorySettings
|
|
30786
30972
|
}) {
|
|
30787
|
-
|
|
30788
|
-
|
|
30789
|
-
|
|
30973
|
+
await auth.ensureUser(c);
|
|
30974
|
+
const tenant = auth.tenant(c);
|
|
30975
|
+
if (!tenant && auth.enabled()) return { response: c.json({ error: "unauthorized" }, 401) };
|
|
30976
|
+
if (memorySettings) {
|
|
30977
|
+
try {
|
|
30978
|
+
await memorySettings.ensureReady();
|
|
30979
|
+
return tenant ? { storage: memorySettings, orgId: tenantOrgId(tenant), userId: tenant.userId } : { storage: memorySettings, orgId: "local", userId: "local" };
|
|
30980
|
+
} catch {
|
|
30981
|
+
}
|
|
30982
|
+
}
|
|
30983
|
+
return {
|
|
30984
|
+
response: c.json(
|
|
30985
|
+
{
|
|
30986
|
+
error: "memory_settings_unavailable",
|
|
30987
|
+
message: "Memory settings storage is unavailable \u2014 the app database is not configured or failed to start."
|
|
30988
|
+
},
|
|
30989
|
+
503
|
|
30990
|
+
)
|
|
30991
|
+
};
|
|
30992
|
+
}
|
|
30993
|
+
async function persistMemorySettings(context, patch, fillIfUnset) {
|
|
30994
|
+
await context.storage.patch({ orgId: context.orgId, userId: context.userId, patch, fillIfUnset });
|
|
30995
|
+
}
|
|
30996
|
+
async function hydrateSessionMemorySettings(session, record) {
|
|
30997
|
+
for (const role of ["observer", "reflector"]) {
|
|
30998
|
+
const stored = role === "observer" ? record?.observerModelId : record?.reflectorModelId;
|
|
30999
|
+
const target = stored ?? DEFAULT_OM_MODEL_ID;
|
|
31000
|
+
if (session.om[role].modelId() !== target) {
|
|
31001
|
+
await session.om[role].switchModel({ modelId: target });
|
|
31002
|
+
}
|
|
31003
|
+
}
|
|
31004
|
+
const state = session.state.get() ?? {};
|
|
31005
|
+
const updates = {};
|
|
31006
|
+
const observationThreshold = record?.observationThreshold ?? DEFAULT_OBSERVATION_THRESHOLD;
|
|
31007
|
+
if (state.observationThreshold !== observationThreshold) {
|
|
31008
|
+
updates.observationThreshold = observationThreshold;
|
|
31009
|
+
}
|
|
31010
|
+
const reflectionThreshold = record?.reflectionThreshold ?? DEFAULT_REFLECTION_THRESHOLD;
|
|
31011
|
+
if (state.reflectionThreshold !== reflectionThreshold) {
|
|
31012
|
+
updates.reflectionThreshold = reflectionThreshold;
|
|
31013
|
+
}
|
|
31014
|
+
const observeAttachments = record?.observeAttachments ?? "auto";
|
|
31015
|
+
if ((state.observeAttachments ?? "auto") !== observeAttachments) {
|
|
31016
|
+
updates.observeAttachments = observeAttachments;
|
|
31017
|
+
}
|
|
31018
|
+
if (Object.keys(updates).length > 0) await session.state.set(updates);
|
|
30790
31019
|
}
|
|
30791
31020
|
var ConfigRoutes = class extends Route {
|
|
30792
31021
|
routes() {
|
|
@@ -30794,6 +31023,8 @@ var ConfigRoutes = class extends Route {
|
|
|
30794
31023
|
const { controller, authStorage, auth } = options;
|
|
30795
31024
|
const onCredentialsChanged = options.onCredentialsChanged ?? (() => {
|
|
30796
31025
|
});
|
|
31026
|
+
const onCustomProvidersChanged = options.onCustomProvidersChanged ?? (() => {
|
|
31027
|
+
});
|
|
30797
31028
|
return [
|
|
30798
31029
|
registerApiRoute7("/web/config/providers", {
|
|
30799
31030
|
method: "GET",
|
|
@@ -30885,14 +31116,22 @@ var ConfigRoutes = class extends Route {
|
|
|
30885
31116
|
}
|
|
30886
31117
|
}),
|
|
30887
31118
|
// ── Custom providers (OpenAI-compatible endpoints) ──────────────────────
|
|
30888
|
-
// Mirrors the TUI's /custom-providers command
|
|
30889
|
-
// (
|
|
31119
|
+
// Mirrors the TUI's /custom-providers command, but backed by the
|
|
31120
|
+
// `custom-providers` domain (org rows in tenant mode, a sentinel `local`
|
|
31121
|
+
// org in no-auth mode) — the server never reads settings.json for these.
|
|
30890
31122
|
registerApiRoute7("/web/config/custom-providers", {
|
|
30891
31123
|
method: "GET",
|
|
30892
31124
|
requiresAuth: false,
|
|
30893
|
-
handler: (c) => {
|
|
31125
|
+
handler: async (c) => {
|
|
31126
|
+
const ctx = await resolveCustomProvidersContext({
|
|
31127
|
+
c: loose6(c),
|
|
31128
|
+
auth,
|
|
31129
|
+
customProviders: options.customProviders
|
|
31130
|
+
});
|
|
31131
|
+
if ("response" in ctx) return ctx.response;
|
|
30894
31132
|
try {
|
|
30895
|
-
|
|
31133
|
+
const records = await ctx.storage.list({ orgId: ctx.orgId });
|
|
31134
|
+
return c.json({ providers: records.map(toCustomProviderInfo) });
|
|
30896
31135
|
} catch (error) {
|
|
30897
31136
|
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
30898
31137
|
}
|
|
@@ -30902,6 +31141,12 @@ var ConfigRoutes = class extends Route {
|
|
|
30902
31141
|
method: "POST",
|
|
30903
31142
|
requiresAuth: false,
|
|
30904
31143
|
handler: async (c) => {
|
|
31144
|
+
const ctx = await resolveCustomProvidersContext({
|
|
31145
|
+
c: loose6(c),
|
|
31146
|
+
auth,
|
|
31147
|
+
customProviders: options.customProviders
|
|
31148
|
+
});
|
|
31149
|
+
if ("response" in ctx) return ctx.response;
|
|
30905
31150
|
let body;
|
|
30906
31151
|
try {
|
|
30907
31152
|
body = await c.req.json();
|
|
@@ -30912,11 +31157,20 @@ var ConfigRoutes = class extends Route {
|
|
|
30912
31157
|
if ("error" in parsed) return c.json({ error: parsed.error }, 400);
|
|
30913
31158
|
const previousId = body && typeof body === "object" && typeof body.previousId === "string" ? body.previousId : void 0;
|
|
30914
31159
|
try {
|
|
30915
|
-
const
|
|
30916
|
-
|
|
30917
|
-
|
|
30918
|
-
|
|
30919
|
-
|
|
31160
|
+
const record = await ctx.storage.upsert({
|
|
31161
|
+
orgId: ctx.orgId,
|
|
31162
|
+
userId: ctx.userId,
|
|
31163
|
+
input: {
|
|
31164
|
+
providerId: getCustomProviderId(parsed.name),
|
|
31165
|
+
name: parsed.name,
|
|
31166
|
+
url: parsed.url,
|
|
31167
|
+
apiKey: parsed.apiKey,
|
|
31168
|
+
models: parsed.models
|
|
31169
|
+
},
|
|
31170
|
+
previousProviderId: previousId
|
|
31171
|
+
});
|
|
31172
|
+
onCustomProvidersChanged({ orgId: ctx.orgId });
|
|
31173
|
+
return c.json({ ok: true, provider: toCustomProviderInfo(record) });
|
|
30920
31174
|
} catch (error) {
|
|
30921
31175
|
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
30922
31176
|
}
|
|
@@ -30925,12 +31179,17 @@ var ConfigRoutes = class extends Route {
|
|
|
30925
31179
|
registerApiRoute7("/web/config/custom-providers/:id", {
|
|
30926
31180
|
method: "DELETE",
|
|
30927
31181
|
requiresAuth: false,
|
|
30928
|
-
handler: (c) => {
|
|
31182
|
+
handler: async (c) => {
|
|
31183
|
+
const ctx = await resolveCustomProvidersContext({
|
|
31184
|
+
c: loose6(c),
|
|
31185
|
+
auth,
|
|
31186
|
+
customProviders: options.customProviders
|
|
31187
|
+
});
|
|
31188
|
+
if ("response" in ctx) return ctx.response;
|
|
30929
31189
|
const id = c.req.param("id");
|
|
30930
31190
|
try {
|
|
30931
|
-
|
|
30932
|
-
|
|
30933
|
-
saveSettings(settings);
|
|
31191
|
+
await ctx.storage.delete({ orgId: ctx.orgId, providerId: id });
|
|
31192
|
+
onCustomProvidersChanged({ orgId: ctx.orgId });
|
|
30934
31193
|
return c.json({ ok: true });
|
|
30935
31194
|
} catch (error) {
|
|
30936
31195
|
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
@@ -30959,8 +31218,30 @@ var ConfigRoutes = class extends Route {
|
|
|
30959
31218
|
tenantCredentials
|
|
30960
31219
|
})
|
|
30961
31220
|
]);
|
|
31221
|
+
const catalog = models.filter((m) => canUseModelProvider(access, m.provider) && typeof m.id === "string").map((m) => ({ id: m.id, provider: m.provider, modelName: m.modelName, hasApiKey: true }));
|
|
31222
|
+
if (options.customProviders) {
|
|
31223
|
+
try {
|
|
31224
|
+
const ctx = await resolveCustomProvidersContext({
|
|
31225
|
+
c: loose6(c),
|
|
31226
|
+
auth,
|
|
31227
|
+
customProviders: options.customProviders
|
|
31228
|
+
});
|
|
31229
|
+
if (!("response" in ctx)) {
|
|
31230
|
+
const known = new Set(catalog.map((m) => m.id));
|
|
31231
|
+
for (const record of await ctx.storage.list({ orgId: ctx.orgId })) {
|
|
31232
|
+
for (const model of record.models) {
|
|
31233
|
+
const id = `${record.providerId}/${model}`;
|
|
31234
|
+
if (known.has(id)) continue;
|
|
31235
|
+
known.add(id);
|
|
31236
|
+
catalog.push({ id, provider: record.providerId, modelName: model, hasApiKey: true });
|
|
31237
|
+
}
|
|
31238
|
+
}
|
|
31239
|
+
}
|
|
31240
|
+
} catch {
|
|
31241
|
+
}
|
|
31242
|
+
}
|
|
30962
31243
|
return c.json({
|
|
30963
|
-
models:
|
|
31244
|
+
models: catalog.sort(
|
|
30964
31245
|
(a, b) => a.provider === b.provider ? a.id.localeCompare(b.id) : a.provider.localeCompare(b.provider)
|
|
30965
31246
|
)
|
|
30966
31247
|
});
|
|
@@ -30970,10 +31251,10 @@ var ConfigRoutes = class extends Route {
|
|
|
30970
31251
|
}
|
|
30971
31252
|
}),
|
|
30972
31253
|
// ── Model packs ─────────────────────────────────────────────────────────
|
|
30973
|
-
// Mirrors the TUI's /models-pack command. Custom-pack CRUD
|
|
30974
|
-
//
|
|
30975
|
-
//
|
|
30976
|
-
// the controller registry by resourceId.
|
|
31254
|
+
// Mirrors the TUI's /models-pack command. Custom-pack CRUD lives in the
|
|
31255
|
+
// model-packs storage domain (org-scoped, sentinel `local` org in no-auth
|
|
31256
|
+
// mode — never settings.json); activation is session-scoped and resolves
|
|
31257
|
+
// the session from the controller registry by resourceId.
|
|
30977
31258
|
registerApiRoute7("/web/config/model-packs", {
|
|
30978
31259
|
method: "GET",
|
|
30979
31260
|
requiresAuth: false,
|
|
@@ -31027,21 +31308,12 @@ var ConfigRoutes = class extends Route {
|
|
|
31027
31308
|
return c.json({ error: "models.build, models.plan and models.fast are required" }, 400);
|
|
31028
31309
|
}
|
|
31029
31310
|
try {
|
|
31030
|
-
|
|
31031
|
-
|
|
31032
|
-
|
|
31033
|
-
|
|
31034
|
-
|
|
31035
|
-
|
|
31036
|
-
return c.json({ ok: true, pack: recordToModePack(record) });
|
|
31037
|
-
}
|
|
31038
|
-
const settings = loadSettings();
|
|
31039
|
-
const entry = { name, models: { build, plan, fast }, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
31040
|
-
const idx = settings.customModelPacks.findIndex((p) => p.name === name);
|
|
31041
|
-
if (idx >= 0) settings.customModelPacks[idx] = entry;
|
|
31042
|
-
else settings.customModelPacks.push(entry);
|
|
31043
|
-
saveSettings(settings);
|
|
31044
|
-
return c.json({ ok: true, pack: { id: `custom:${name}`, name, models: { build, plan, fast } } });
|
|
31311
|
+
const record = await packContext.storage.upsert({
|
|
31312
|
+
orgId: packContext.orgId,
|
|
31313
|
+
userId: packContext.userId,
|
|
31314
|
+
input: { name, models: { build, plan, fast } }
|
|
31315
|
+
});
|
|
31316
|
+
return c.json({ ok: true, pack: recordToModePack(record) });
|
|
31045
31317
|
} catch (error) {
|
|
31046
31318
|
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
31047
31319
|
}
|
|
@@ -31055,15 +31327,9 @@ var ConfigRoutes = class extends Route {
|
|
|
31055
31327
|
if ("response" in packContext) return packContext.response;
|
|
31056
31328
|
const id = decodeURIComponent(c.req.param("id"));
|
|
31057
31329
|
try {
|
|
31058
|
-
|
|
31059
|
-
|
|
31060
|
-
|
|
31061
|
-
return deleted ? c.json({ ok: true }) : c.json({ error: `Unknown pack "${id}"` }, 404);
|
|
31062
|
-
}
|
|
31063
|
-
const settings = loadSettings();
|
|
31064
|
-
removeCustomPackFromSettings(settings, id);
|
|
31065
|
-
saveSettings(settings);
|
|
31066
|
-
return c.json({ ok: true });
|
|
31330
|
+
const recordId = id.startsWith("custom:") ? id.slice("custom:".length) : id;
|
|
31331
|
+
const deleted = await packContext.storage.delete({ orgId: packContext.orgId, id: recordId });
|
|
31332
|
+
return deleted ? c.json({ ok: true }) : c.json({ error: `Unknown pack "${id}"` }, 404);
|
|
31067
31333
|
} catch (error) {
|
|
31068
31334
|
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
31069
31335
|
}
|
|
@@ -31110,8 +31376,10 @@ var ConfigRoutes = class extends Route {
|
|
|
31110
31376
|
}),
|
|
31111
31377
|
// ── Observational memory ──────────────────────────────────────────────────
|
|
31112
31378
|
// Mirrors the TUI's /om command. All five knobs are session-scoped (resolved
|
|
31113
|
-
// from the session, persisted to its state + thread setting)
|
|
31114
|
-
//
|
|
31379
|
+
// from the session, persisted to its state + thread setting) and durably
|
|
31380
|
+
// stored in the per-(org, user) `memory-settings` app table — never
|
|
31381
|
+
// settings.json. GET hydrates the session from the stored row first so the
|
|
31382
|
+
// DB, not the SDK's boot-time seed, is the source of truth.
|
|
31115
31383
|
registerApiRoute7("/web/config/om", {
|
|
31116
31384
|
method: "GET",
|
|
31117
31385
|
requiresAuth: false,
|
|
@@ -31119,9 +31387,17 @@ var ConfigRoutes = class extends Route {
|
|
|
31119
31387
|
const resourceId = c.req.query("resourceId");
|
|
31120
31388
|
const scope = c.req.query("scope") || void 0;
|
|
31121
31389
|
if (!resourceId) return c.json({ error: "Missing required query param: resourceId" }, 400);
|
|
31390
|
+
const context = await resolveMemorySettingsContext({
|
|
31391
|
+
c: loose6(c),
|
|
31392
|
+
auth,
|
|
31393
|
+
memorySettings: options.memorySettings
|
|
31394
|
+
});
|
|
31395
|
+
if ("response" in context) return context.response;
|
|
31122
31396
|
try {
|
|
31123
31397
|
const session = await controller.getSessionByResource?.(resourceId, scope);
|
|
31124
31398
|
if (!session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
|
|
31399
|
+
const record = await context.storage.get({ orgId: context.orgId, userId: context.userId });
|
|
31400
|
+
await hydrateSessionMemorySettings(session, record);
|
|
31125
31401
|
return c.json({ config: readOMConfig(session) });
|
|
31126
31402
|
} catch (error) {
|
|
31127
31403
|
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
@@ -31147,13 +31423,24 @@ var ConfigRoutes = class extends Route {
|
|
|
31147
31423
|
const modelId = typeof body.modelId === "string" ? body.modelId.trim() : "";
|
|
31148
31424
|
if (!resourceId) return c.json({ error: "Missing required field: resourceId" }, 400);
|
|
31149
31425
|
if (!modelId) return c.json({ error: "Missing required field: modelId" }, 400);
|
|
31426
|
+
const context = await resolveMemorySettingsContext({
|
|
31427
|
+
c: loose6(c),
|
|
31428
|
+
auth,
|
|
31429
|
+
memorySettings: options.memorySettings
|
|
31430
|
+
});
|
|
31431
|
+
if ("response" in context) return context.response;
|
|
31150
31432
|
try {
|
|
31151
31433
|
const session = await controller.getSessionByResource?.(resourceId, scope);
|
|
31152
31434
|
if (!session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
|
|
31153
31435
|
const otherRole = role === "observer" ? session.om.reflector : session.om.observer;
|
|
31154
31436
|
const otherRoleCurrentModelId = otherRole.modelId() ?? null;
|
|
31155
31437
|
await session.om[role].switchModel({ modelId });
|
|
31156
|
-
|
|
31438
|
+
const otherKey = role === "observer" ? "reflectorModelId" : "observerModelId";
|
|
31439
|
+
await persistMemorySettings(
|
|
31440
|
+
context,
|
|
31441
|
+
{ [role === "observer" ? "observerModelId" : "reflectorModelId"]: modelId },
|
|
31442
|
+
otherRoleCurrentModelId ? { [otherKey]: otherRoleCurrentModelId } : void 0
|
|
31443
|
+
);
|
|
31157
31444
|
return c.json({ ok: true, config: readOMConfig(session) });
|
|
31158
31445
|
} catch (error) {
|
|
31159
31446
|
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
@@ -31178,19 +31465,27 @@ var ConfigRoutes = class extends Route {
|
|
|
31178
31465
|
if (observation === void 0 && reflection === void 0) {
|
|
31179
31466
|
return c.json({ error: "Provide observationThreshold and/or reflectionThreshold (positive numbers)" }, 400);
|
|
31180
31467
|
}
|
|
31468
|
+
const context = await resolveMemorySettingsContext({
|
|
31469
|
+
c: loose6(c),
|
|
31470
|
+
auth,
|
|
31471
|
+
memorySettings: options.memorySettings
|
|
31472
|
+
});
|
|
31473
|
+
if ("response" in context) return context.response;
|
|
31181
31474
|
try {
|
|
31182
31475
|
const session = await controller.getSessionByResource?.(resourceId, scope);
|
|
31183
31476
|
if (!session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
|
|
31184
31477
|
if (observation !== void 0) {
|
|
31185
31478
|
await session.state.set({ observationThreshold: observation });
|
|
31186
31479
|
await session.thread.setSetting({ key: "observationThreshold", value: observation });
|
|
31187
|
-
persistOmThreshold({ role: "observation", value: observation });
|
|
31188
31480
|
}
|
|
31189
31481
|
if (reflection !== void 0) {
|
|
31190
31482
|
await session.state.set({ reflectionThreshold: reflection });
|
|
31191
31483
|
await session.thread.setSetting({ key: "reflectionThreshold", value: reflection });
|
|
31192
|
-
persistOmThreshold({ role: "reflection", value: reflection });
|
|
31193
31484
|
}
|
|
31485
|
+
await persistMemorySettings(context, {
|
|
31486
|
+
...observation !== void 0 ? { observationThreshold: observation } : {},
|
|
31487
|
+
...reflection !== void 0 ? { reflectionThreshold: reflection } : {}
|
|
31488
|
+
});
|
|
31194
31489
|
return c.json({ ok: true, config: readOMConfig(session) });
|
|
31195
31490
|
} catch (error) {
|
|
31196
31491
|
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
@@ -31215,12 +31510,18 @@ var ConfigRoutes = class extends Route {
|
|
|
31215
31510
|
if (raw !== "auto" && raw !== true && raw !== false) {
|
|
31216
31511
|
return c.json({ error: "value must be 'auto', true, or false" }, 400);
|
|
31217
31512
|
}
|
|
31513
|
+
const context = await resolveMemorySettingsContext({
|
|
31514
|
+
c: loose6(c),
|
|
31515
|
+
auth,
|
|
31516
|
+
memorySettings: options.memorySettings
|
|
31517
|
+
});
|
|
31518
|
+
if ("response" in context) return context.response;
|
|
31218
31519
|
try {
|
|
31219
31520
|
const session = await controller.getSessionByResource?.(resourceId, scope);
|
|
31220
31521
|
if (!session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
|
|
31221
31522
|
await session.state.set({ observeAttachments: value });
|
|
31222
31523
|
await session.thread.setSetting({ key: "observeAttachments", value });
|
|
31223
|
-
|
|
31524
|
+
await persistMemorySettings(context, { observeAttachments: value });
|
|
31224
31525
|
return c.json({ ok: true, config: readOMConfig(session) });
|
|
31225
31526
|
} catch (error) {
|
|
31226
31527
|
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
@@ -32438,7 +32739,7 @@ var SkillRoutes = class extends Route {
|
|
|
32438
32739
|
// src/routes/tenant-credentials.ts
|
|
32439
32740
|
import { setCredentialStoreProvider } from "@mastra/code-sdk/agents/credential-resolver";
|
|
32440
32741
|
import { getOAuthProvider } from "@mastra/code-sdk/auth/storage";
|
|
32441
|
-
var
|
|
32742
|
+
var SNAPSHOT_TTL_MS2 = 15e3;
|
|
32442
32743
|
var MAX_CACHED_TENANTS = 1e3;
|
|
32443
32744
|
var TenantCredentialStore = class {
|
|
32444
32745
|
allowEnvironmentFallback = false;
|
|
@@ -32455,7 +32756,7 @@ var TenantCredentialStore = class {
|
|
|
32455
32756
|
}
|
|
32456
32757
|
/** Hydrate the snapshot when stale; coalesces concurrent callers. */
|
|
32457
32758
|
async ensureFresh(now = Date.now()) {
|
|
32458
|
-
if (now - this.#fetchedAt <
|
|
32759
|
+
if (now - this.#fetchedAt < SNAPSHOT_TTL_MS2) return;
|
|
32459
32760
|
this.#hydrating ??= this.#hydrate().finally(() => {
|
|
32460
32761
|
this.#hydrating = void 0;
|
|
32461
32762
|
});
|
|
@@ -32477,7 +32778,7 @@ var TenantCredentialStore = class {
|
|
|
32477
32778
|
}
|
|
32478
32779
|
/** Sync by contract; kicks a background re-hydrate when the snapshot is stale. */
|
|
32479
32780
|
reload() {
|
|
32480
|
-
if (Date.now() - this.#fetchedAt >=
|
|
32781
|
+
if (Date.now() - this.#fetchedAt >= SNAPSHOT_TTL_MS2) {
|
|
32481
32782
|
void this.ensureFresh().catch(() => {
|
|
32482
32783
|
});
|
|
32483
32784
|
}
|
|
@@ -34813,6 +35114,7 @@ function assembleFactoryApiRoutes(deps) {
|
|
|
34813
35114
|
github: githubIntegration,
|
|
34814
35115
|
sourceControl: githubStorage,
|
|
34815
35116
|
integrationStorage: deps.integrationStorage.forIntegration("github"),
|
|
35117
|
+
projects: deps.domains.projects,
|
|
34816
35118
|
storage: workItems,
|
|
34817
35119
|
rules: deps.rules
|
|
34818
35120
|
}) : void 0;
|
|
@@ -34860,7 +35162,10 @@ function assembleFactoryApiRoutes(deps) {
|
|
|
34860
35162
|
authStorage: deps.authStorage,
|
|
34861
35163
|
modelCredentials: deps.domains.modelCredentials,
|
|
34862
35164
|
modelPacks: deps.domains.modelPacks,
|
|
34863
|
-
|
|
35165
|
+
memorySettings: deps.domains.memorySettings,
|
|
35166
|
+
customProviders: deps.domains.customProviders,
|
|
35167
|
+
onCredentialsChanged: invalidateTenantCredentialSnapshots,
|
|
35168
|
+
onCustomProvidersChanged: invalidateCustomProvidersSnapshots
|
|
34864
35169
|
}).routes(),
|
|
34865
35170
|
...new OAuthRoutes({
|
|
34866
35171
|
auth: deps.auth,
|
|
@@ -34950,6 +35255,12 @@ function advanceApprovedPlan(context) {
|
|
|
34950
35255
|
stage: "execute"
|
|
34951
35256
|
};
|
|
34952
35257
|
}
|
|
35258
|
+
function createdAfterFactory(createdAt, factoryCreatedAt) {
|
|
35259
|
+
if (!createdAt) return false;
|
|
35260
|
+
const sourceCreatedAt = Date.parse(createdAt);
|
|
35261
|
+
const projectCreatedAt = Date.parse(factoryCreatedAt);
|
|
35262
|
+
return Number.isFinite(sourceCreatedAt) && Number.isFinite(projectCreatedAt) && sourceCreatedAt > projectCreatedAt;
|
|
35263
|
+
}
|
|
34953
35264
|
function issueOpened(context) {
|
|
34954
35265
|
if (!context.issue) return;
|
|
34955
35266
|
return {
|
|
@@ -34960,7 +35271,7 @@ function issueOpened(context) {
|
|
|
34960
35271
|
sourceKey: `github-issue:${context.issue.number}`,
|
|
34961
35272
|
title: context.issue.title,
|
|
34962
35273
|
url: context.issue.url,
|
|
34963
|
-
stage: trustedGithubActor(context) ? "triage" : "intake",
|
|
35274
|
+
stage: trustedGithubActor(context) && createdAfterFactory(context.issue.createdAt, context.factory.createdAt) ? "triage" : "intake",
|
|
34964
35275
|
metadata: {
|
|
34965
35276
|
githubRepositoryId: context.repository.id,
|
|
34966
35277
|
githubIssueNumber: context.issue.number
|
|
@@ -34977,7 +35288,7 @@ function pullRequestOpened(context) {
|
|
|
34977
35288
|
sourceKey: `github-pr:${context.pullRequest.number}`,
|
|
34978
35289
|
title: context.pullRequest.title,
|
|
34979
35290
|
url: context.pullRequest.url,
|
|
34980
|
-
stage: trustedGithubActor(context) ? "review" : "intake",
|
|
35291
|
+
stage: trustedGithubActor(context) && createdAfterFactory(context.pullRequest.createdAt, context.factory.createdAt) ? "review" : "intake",
|
|
34981
35292
|
metadata: {
|
|
34982
35293
|
githubRepositoryId: context.repository.id,
|
|
34983
35294
|
githubPullRequestNumber: context.pullRequest.number,
|
|
@@ -36019,10 +36330,13 @@ var MIME = {
|
|
|
36019
36330
|
};
|
|
36020
36331
|
var SERVER_PREFIXES = ["/api", "/web", "/auth"];
|
|
36021
36332
|
function resolveUiDistDir() {
|
|
36333
|
+
const projectRoot = process.env.MASTRA_PROJECT_ROOT?.trim();
|
|
36022
36334
|
const candidates = [
|
|
36023
36335
|
process.env.MASTRACODE_UI_DIST,
|
|
36024
|
-
|
|
36025
|
-
|
|
36336
|
+
resolve2(process.cwd(), "factory"),
|
|
36337
|
+
join2(dirname(fileURLToPath(import.meta.url)), "factory"),
|
|
36338
|
+
projectRoot && resolve2(projectRoot, "src/mastra/public/factory"),
|
|
36339
|
+
resolve2(process.cwd(), "src/mastra/public/factory")
|
|
36026
36340
|
];
|
|
36027
36341
|
for (const candidate of candidates) {
|
|
36028
36342
|
if (candidate && existsSync(join2(candidate, "index.html"))) return resolve2(candidate);
|
|
@@ -36448,8 +36762,154 @@ var AuditDomain = class {
|
|
|
36448
36762
|
}
|
|
36449
36763
|
};
|
|
36450
36764
|
|
|
36451
|
-
// src/storage/domains/
|
|
36765
|
+
// src/storage/domains/custom-providers/base.ts
|
|
36452
36766
|
import { FactoryStorageDomain as FactoryStorageDomain5, UniqueViolationError as UniqueViolationError5 } from "@mastra/core/storage";
|
|
36767
|
+
var CUSTOM_PROVIDERS_SCHEMA = {
|
|
36768
|
+
name: "custom_providers",
|
|
36769
|
+
columns: {
|
|
36770
|
+
id: { type: "uuid-pk" },
|
|
36771
|
+
org_id: { type: "text" },
|
|
36772
|
+
created_by: { type: "text" },
|
|
36773
|
+
provider_id: { type: "text" },
|
|
36774
|
+
name: { type: "text" },
|
|
36775
|
+
url: { type: "text" },
|
|
36776
|
+
api_key: { type: "text", nullable: true },
|
|
36777
|
+
models: { type: "json" },
|
|
36778
|
+
created_at: { type: "timestamp" },
|
|
36779
|
+
updated_at: { type: "timestamp" }
|
|
36780
|
+
},
|
|
36781
|
+
uniqueIndexes: [{ name: "custom_providers_org_provider_key", columns: ["org_id", "provider_id"] }]
|
|
36782
|
+
};
|
|
36783
|
+
function toRecord(row) {
|
|
36784
|
+
return {
|
|
36785
|
+
id: row.id,
|
|
36786
|
+
orgId: row.org_id,
|
|
36787
|
+
createdBy: row.created_by,
|
|
36788
|
+
providerId: row.provider_id,
|
|
36789
|
+
name: row.name,
|
|
36790
|
+
url: row.url,
|
|
36791
|
+
apiKey: row.api_key,
|
|
36792
|
+
models: Array.isArray(row.models) ? row.models : [],
|
|
36793
|
+
createdAt: row.created_at,
|
|
36794
|
+
updatedAt: row.updated_at
|
|
36795
|
+
};
|
|
36796
|
+
}
|
|
36797
|
+
var CustomProvidersStorage = class extends FactoryStorageDomain5 {
|
|
36798
|
+
constructor() {
|
|
36799
|
+
super("custom-providers");
|
|
36800
|
+
}
|
|
36801
|
+
async init() {
|
|
36802
|
+
await this.ensureCollections([CUSTOM_PROVIDERS_SCHEMA]);
|
|
36803
|
+
}
|
|
36804
|
+
async dangerouslyClearAll() {
|
|
36805
|
+
await this.ops.deleteMany("custom_providers", {});
|
|
36806
|
+
}
|
|
36807
|
+
get #db() {
|
|
36808
|
+
return this.ops;
|
|
36809
|
+
}
|
|
36810
|
+
/**
|
|
36811
|
+
* Create or wholesale-replace a provider by `(orgId, providerId)` — mirrors
|
|
36812
|
+
* the settings.json upsert semantics (no key retention: an absent `apiKey`
|
|
36813
|
+
* clears the stored key). `previousProviderId` renames the provider: the
|
|
36814
|
+
* common path is a single atomic in-place update of the old row; renaming
|
|
36815
|
+
* onto an id that already exists overwrites the target first and removes the
|
|
36816
|
+
* old row last, so no interleaving or failure can lose the provider.
|
|
36817
|
+
*/
|
|
36818
|
+
async upsert({
|
|
36819
|
+
orgId,
|
|
36820
|
+
userId,
|
|
36821
|
+
input,
|
|
36822
|
+
previousProviderId
|
|
36823
|
+
}) {
|
|
36824
|
+
const now = /* @__PURE__ */ new Date();
|
|
36825
|
+
const renameFrom = previousProviderId && previousProviderId !== input.providerId ? previousProviderId : void 0;
|
|
36826
|
+
if (renameFrom) {
|
|
36827
|
+
const target = await this.#db.findOne("custom_providers", {
|
|
36828
|
+
org_id: orgId,
|
|
36829
|
+
provider_id: input.providerId
|
|
36830
|
+
});
|
|
36831
|
+
if (!target) {
|
|
36832
|
+
const renamed = await this.#db.updateAtomic(
|
|
36833
|
+
"custom_providers",
|
|
36834
|
+
{ org_id: orgId, provider_id: renameFrom },
|
|
36835
|
+
() => ({
|
|
36836
|
+
provider_id: input.providerId,
|
|
36837
|
+
name: input.name,
|
|
36838
|
+
url: input.url,
|
|
36839
|
+
api_key: input.apiKey ?? null,
|
|
36840
|
+
models: input.models,
|
|
36841
|
+
updated_at: now
|
|
36842
|
+
})
|
|
36843
|
+
);
|
|
36844
|
+
if (renamed) return toRecord(renamed);
|
|
36845
|
+
}
|
|
36846
|
+
}
|
|
36847
|
+
const record = await this.#write({ orgId, userId, input, now });
|
|
36848
|
+
if (renameFrom) {
|
|
36849
|
+
await this.#db.deleteMany("custom_providers", { org_id: orgId, provider_id: renameFrom });
|
|
36850
|
+
}
|
|
36851
|
+
return record;
|
|
36852
|
+
}
|
|
36853
|
+
/**
|
|
36854
|
+
* Update-first, then insert-and-catch-unique-violation (see `queue_health`):
|
|
36855
|
+
* concurrent creates of the same provider both succeed (last write wins on
|
|
36856
|
+
* the single row) instead of one failing on the unique index, and a row
|
|
36857
|
+
* deleted mid-flight is recreated rather than reported as a stale success.
|
|
36858
|
+
*/
|
|
36859
|
+
async #write({
|
|
36860
|
+
orgId,
|
|
36861
|
+
userId,
|
|
36862
|
+
input,
|
|
36863
|
+
now
|
|
36864
|
+
}) {
|
|
36865
|
+
const updateExisting = () => this.#db.updateAtomic(
|
|
36866
|
+
"custom_providers",
|
|
36867
|
+
{ org_id: orgId, provider_id: input.providerId },
|
|
36868
|
+
() => ({
|
|
36869
|
+
name: input.name,
|
|
36870
|
+
url: input.url,
|
|
36871
|
+
api_key: input.apiKey ?? null,
|
|
36872
|
+
models: input.models,
|
|
36873
|
+
updated_at: now
|
|
36874
|
+
})
|
|
36875
|
+
);
|
|
36876
|
+
const updated = await updateExisting();
|
|
36877
|
+
if (updated) return toRecord(updated);
|
|
36878
|
+
try {
|
|
36879
|
+
const row = await this.#db.insertOne("custom_providers", {
|
|
36880
|
+
org_id: orgId,
|
|
36881
|
+
created_by: userId,
|
|
36882
|
+
provider_id: input.providerId,
|
|
36883
|
+
name: input.name,
|
|
36884
|
+
url: input.url,
|
|
36885
|
+
api_key: input.apiKey ?? null,
|
|
36886
|
+
models: input.models,
|
|
36887
|
+
created_at: now,
|
|
36888
|
+
updated_at: now
|
|
36889
|
+
});
|
|
36890
|
+
return toRecord(row);
|
|
36891
|
+
} catch (error) {
|
|
36892
|
+
if (!(error instanceof UniqueViolationError5)) throw error;
|
|
36893
|
+
const row = await updateExisting();
|
|
36894
|
+
if (!row) throw error;
|
|
36895
|
+
return toRecord(row);
|
|
36896
|
+
}
|
|
36897
|
+
}
|
|
36898
|
+
async list({ orgId }) {
|
|
36899
|
+
const rows = await this.#db.findMany(
|
|
36900
|
+
"custom_providers",
|
|
36901
|
+
{ org_id: orgId },
|
|
36902
|
+
{ orderBy: [["name", "asc"]] }
|
|
36903
|
+
);
|
|
36904
|
+
return rows.map(toRecord);
|
|
36905
|
+
}
|
|
36906
|
+
async delete({ orgId, providerId }) {
|
|
36907
|
+
return await this.#db.deleteMany("custom_providers", { org_id: orgId, provider_id: providerId }) > 0;
|
|
36908
|
+
}
|
|
36909
|
+
};
|
|
36910
|
+
|
|
36911
|
+
// src/storage/domains/intake/base.ts
|
|
36912
|
+
import { FactoryStorageDomain as FactoryStorageDomain6, UniqueViolationError as UniqueViolationError6 } from "@mastra/core/storage";
|
|
36453
36913
|
var DEFAULT_INTAKE_CONFIG = {};
|
|
36454
36914
|
var INTAKE_SETTINGS_SCHEMA = {
|
|
36455
36915
|
name: "intake_settings",
|
|
@@ -36463,7 +36923,7 @@ var INTAKE_SETTINGS_SCHEMA = {
|
|
|
36463
36923
|
},
|
|
36464
36924
|
uniqueIndexes: [{ name: "intake_settings_org_user_unique", columns: ["org_id", "user_id"] }]
|
|
36465
36925
|
};
|
|
36466
|
-
var IntakeStorage = class extends
|
|
36926
|
+
var IntakeStorage = class extends FactoryStorageDomain6 {
|
|
36467
36927
|
constructor() {
|
|
36468
36928
|
super("intake");
|
|
36469
36929
|
}
|
|
@@ -36499,14 +36959,14 @@ var IntakeStorage = class extends FactoryStorageDomain5 {
|
|
|
36499
36959
|
try {
|
|
36500
36960
|
await this.#db.insertOne("intake_settings", { ...where, config, created_at: now, updated_at: now });
|
|
36501
36961
|
} catch (error) {
|
|
36502
|
-
if (!(error instanceof
|
|
36962
|
+
if (!(error instanceof UniqueViolationError6)) throw error;
|
|
36503
36963
|
await this.#db.updateMany("intake_settings", where, { config, updated_at: now });
|
|
36504
36964
|
}
|
|
36505
36965
|
}
|
|
36506
36966
|
};
|
|
36507
36967
|
|
|
36508
36968
|
// src/storage/domains/integrations/base.ts
|
|
36509
|
-
import { FactoryStorageDomain as
|
|
36969
|
+
import { FactoryStorageDomain as FactoryStorageDomain7, UniqueViolationError as UniqueViolationError7 } from "@mastra/core/storage";
|
|
36510
36970
|
var INTEGRATION_CONNECTIONS_SCHEMA = {
|
|
36511
36971
|
name: "integration_connections",
|
|
36512
36972
|
columns: {
|
|
@@ -36559,7 +37019,7 @@ var INTEGRATION_SETTINGS_SCHEMA = {
|
|
|
36559
37019
|
{ name: "integration_settings_integration_org_user_unique", columns: ["integration_id", "org_id", "user_id"] }
|
|
36560
37020
|
]
|
|
36561
37021
|
};
|
|
36562
|
-
var IntegrationStorage = class extends
|
|
37022
|
+
var IntegrationStorage = class extends FactoryStorageDomain7 {
|
|
36563
37023
|
constructor() {
|
|
36564
37024
|
super("integrations");
|
|
36565
37025
|
}
|
|
@@ -36635,7 +37095,7 @@ var IntegrationStorage = class extends FactoryStorageDomain6 {
|
|
|
36635
37095
|
});
|
|
36636
37096
|
return;
|
|
36637
37097
|
} catch (error) {
|
|
36638
|
-
if (!(error instanceof
|
|
37098
|
+
if (!(error instanceof UniqueViolationError7)) throw error;
|
|
36639
37099
|
lastError = error;
|
|
36640
37100
|
}
|
|
36641
37101
|
}
|
|
@@ -36740,7 +37200,7 @@ var IntegrationStorage = class extends FactoryStorageDomain6 {
|
|
|
36740
37200
|
});
|
|
36741
37201
|
return;
|
|
36742
37202
|
} catch (error) {
|
|
36743
|
-
if (!(error instanceof
|
|
37203
|
+
if (!(error instanceof UniqueViolationError7)) throw error;
|
|
36744
37204
|
lastError = error;
|
|
36745
37205
|
}
|
|
36746
37206
|
}
|
|
@@ -36751,8 +37211,115 @@ var IntegrationStorage = class extends FactoryStorageDomain6 {
|
|
|
36751
37211
|
}
|
|
36752
37212
|
};
|
|
36753
37213
|
|
|
37214
|
+
// src/storage/domains/memory-settings/base.ts
|
|
37215
|
+
import { FactoryStorageDomain as FactoryStorageDomain8, UniqueViolationError as UniqueViolationError8 } from "@mastra/core/storage";
|
|
37216
|
+
var MEMORY_SETTINGS_SCHEMA = {
|
|
37217
|
+
name: "memory_settings",
|
|
37218
|
+
columns: {
|
|
37219
|
+
id: { type: "uuid-pk" },
|
|
37220
|
+
org_id: { type: "text" },
|
|
37221
|
+
user_id: { type: "text" },
|
|
37222
|
+
observer_model_id: { type: "text", nullable: true },
|
|
37223
|
+
reflector_model_id: { type: "text", nullable: true },
|
|
37224
|
+
observation_threshold: { type: "integer", nullable: true },
|
|
37225
|
+
reflection_threshold: { type: "integer", nullable: true },
|
|
37226
|
+
// 'auto' | true | false — json keeps the tri-state without string encoding.
|
|
37227
|
+
observe_attachments: { type: "json", nullable: true },
|
|
37228
|
+
created_at: { type: "timestamp" },
|
|
37229
|
+
updated_at: { type: "timestamp" }
|
|
37230
|
+
},
|
|
37231
|
+
uniqueIndexes: [{ name: "memory_settings_org_user_key", columns: ["org_id", "user_id"] }]
|
|
37232
|
+
};
|
|
37233
|
+
function toRecord2(row) {
|
|
37234
|
+
return {
|
|
37235
|
+
orgId: row.org_id,
|
|
37236
|
+
userId: row.user_id,
|
|
37237
|
+
observerModelId: row.observer_model_id,
|
|
37238
|
+
reflectorModelId: row.reflector_model_id,
|
|
37239
|
+
observationThreshold: row.observation_threshold,
|
|
37240
|
+
reflectionThreshold: row.reflection_threshold,
|
|
37241
|
+
observeAttachments: row.observe_attachments,
|
|
37242
|
+
createdAt: row.created_at,
|
|
37243
|
+
updatedAt: row.updated_at
|
|
37244
|
+
};
|
|
37245
|
+
}
|
|
37246
|
+
function patchToColumns(patch) {
|
|
37247
|
+
const columns = {};
|
|
37248
|
+
if (patch.observerModelId !== void 0) columns.observer_model_id = patch.observerModelId;
|
|
37249
|
+
if (patch.reflectorModelId !== void 0) columns.reflector_model_id = patch.reflectorModelId;
|
|
37250
|
+
if (patch.observationThreshold !== void 0) columns.observation_threshold = patch.observationThreshold;
|
|
37251
|
+
if (patch.reflectionThreshold !== void 0) columns.reflection_threshold = patch.reflectionThreshold;
|
|
37252
|
+
if (patch.observeAttachments !== void 0) columns.observe_attachments = patch.observeAttachments;
|
|
37253
|
+
return columns;
|
|
37254
|
+
}
|
|
37255
|
+
var MemorySettingsStorage = class extends FactoryStorageDomain8 {
|
|
37256
|
+
constructor() {
|
|
37257
|
+
super("memory-settings");
|
|
37258
|
+
}
|
|
37259
|
+
async init() {
|
|
37260
|
+
await this.ensureCollections([MEMORY_SETTINGS_SCHEMA]);
|
|
37261
|
+
}
|
|
37262
|
+
async dangerouslyClearAll() {
|
|
37263
|
+
await this.ops.deleteMany("memory_settings", {});
|
|
37264
|
+
}
|
|
37265
|
+
get #db() {
|
|
37266
|
+
return this.ops;
|
|
37267
|
+
}
|
|
37268
|
+
async get({ orgId, userId }) {
|
|
37269
|
+
const row = await this.#db.findOne("memory_settings", { org_id: orgId, user_id: userId });
|
|
37270
|
+
return row ? toRecord2(row) : null;
|
|
37271
|
+
}
|
|
37272
|
+
/**
|
|
37273
|
+
* Upsert the user's row, writing only the knobs present in `patch`.
|
|
37274
|
+
* `fillIfUnset` knobs are written only where the stored value is still
|
|
37275
|
+
* `NULL`, decided inside the atomic update so concurrent explicit writes
|
|
37276
|
+
* win over fills. Concurrent first writes are resolved via the shared
|
|
37277
|
+
* insert-then-catch-unique-violation pattern (see `queue_health`).
|
|
37278
|
+
*/
|
|
37279
|
+
async patch({
|
|
37280
|
+
orgId,
|
|
37281
|
+
userId,
|
|
37282
|
+
patch,
|
|
37283
|
+
fillIfUnset
|
|
37284
|
+
}) {
|
|
37285
|
+
const now = /* @__PURE__ */ new Date();
|
|
37286
|
+
const updateExisting = () => this.#db.updateAtomic("memory_settings", { org_id: orgId, user_id: userId }, (row) => {
|
|
37287
|
+
const columns = { ...patchToColumns(patch), updated_at: now };
|
|
37288
|
+
if (fillIfUnset?.observerModelId !== void 0 && row.observer_model_id == null) {
|
|
37289
|
+
columns.observer_model_id = patch.observerModelId ?? fillIfUnset.observerModelId;
|
|
37290
|
+
}
|
|
37291
|
+
if (fillIfUnset?.reflectorModelId !== void 0 && row.reflector_model_id == null) {
|
|
37292
|
+
columns.reflector_model_id = patch.reflectorModelId ?? fillIfUnset.reflectorModelId;
|
|
37293
|
+
}
|
|
37294
|
+
return columns;
|
|
37295
|
+
});
|
|
37296
|
+
const updated = await updateExisting();
|
|
37297
|
+
if (updated) return toRecord2(updated);
|
|
37298
|
+
try {
|
|
37299
|
+
const row = await this.#db.insertOne("memory_settings", {
|
|
37300
|
+
org_id: orgId,
|
|
37301
|
+
user_id: userId,
|
|
37302
|
+
observer_model_id: fillIfUnset?.observerModelId ?? null,
|
|
37303
|
+
reflector_model_id: fillIfUnset?.reflectorModelId ?? null,
|
|
37304
|
+
observation_threshold: null,
|
|
37305
|
+
reflection_threshold: null,
|
|
37306
|
+
observe_attachments: null,
|
|
37307
|
+
...patchToColumns(patch),
|
|
37308
|
+
created_at: now,
|
|
37309
|
+
updated_at: now
|
|
37310
|
+
});
|
|
37311
|
+
return toRecord2(row);
|
|
37312
|
+
} catch (error) {
|
|
37313
|
+
if (!(error instanceof UniqueViolationError8)) throw error;
|
|
37314
|
+
const row = await updateExisting();
|
|
37315
|
+
if (!row) throw error;
|
|
37316
|
+
return toRecord2(row);
|
|
37317
|
+
}
|
|
37318
|
+
}
|
|
37319
|
+
};
|
|
37320
|
+
|
|
36754
37321
|
// src/storage/domains/model-packs/base.ts
|
|
36755
|
-
import { FactoryStorageDomain as
|
|
37322
|
+
import { FactoryStorageDomain as FactoryStorageDomain9 } from "@mastra/core/storage";
|
|
36756
37323
|
var MODEL_PACKS_SCHEMA = {
|
|
36757
37324
|
name: "model_packs",
|
|
36758
37325
|
columns: {
|
|
@@ -36779,7 +37346,7 @@ function toModelPack(row) {
|
|
|
36779
37346
|
updatedAt: row.updated_at
|
|
36780
37347
|
};
|
|
36781
37348
|
}
|
|
36782
|
-
var ModelPacksStorage = class extends
|
|
37349
|
+
var ModelPacksStorage = class extends FactoryStorageDomain9 {
|
|
36783
37350
|
constructor() {
|
|
36784
37351
|
super("model-packs");
|
|
36785
37352
|
}
|
|
@@ -36843,7 +37410,7 @@ var ModelPacksStorage = class extends FactoryStorageDomain7 {
|
|
|
36843
37410
|
};
|
|
36844
37411
|
|
|
36845
37412
|
// src/storage/domains/projects/base.ts
|
|
36846
|
-
import { FactoryStorageDomain as
|
|
37413
|
+
import { FactoryStorageDomain as FactoryStorageDomain10 } from "@mastra/core/storage";
|
|
36847
37414
|
var FACTORY_PROJECTS_SCHEMA = {
|
|
36848
37415
|
name: "factory_projects",
|
|
36849
37416
|
columns: {
|
|
@@ -36870,7 +37437,7 @@ function toFactoryProject(row) {
|
|
|
36870
37437
|
updatedAt: row.updated_at
|
|
36871
37438
|
};
|
|
36872
37439
|
}
|
|
36873
|
-
var FactoryProjectsStorage = class extends
|
|
37440
|
+
var FactoryProjectsStorage = class extends FactoryStorageDomain10 {
|
|
36874
37441
|
constructor() {
|
|
36875
37442
|
super("projects");
|
|
36876
37443
|
}
|
|
@@ -36938,7 +37505,7 @@ var FactoryProjectsStorage = class extends FactoryStorageDomain8 {
|
|
|
36938
37505
|
};
|
|
36939
37506
|
|
|
36940
37507
|
// src/storage/domains/source-control/base.ts
|
|
36941
|
-
import { FactoryStorageDomain as
|
|
37508
|
+
import { FactoryStorageDomain as FactoryStorageDomain11, UniqueViolationError as UniqueViolationError9 } from "@mastra/core/storage";
|
|
36942
37509
|
var FACTORY_PROJECTS = "factory_projects";
|
|
36943
37510
|
var INSTALLATIONS = "source_control_installations";
|
|
36944
37511
|
var REPOSITORIES = "source_control_repositories";
|
|
@@ -37191,7 +37758,7 @@ function toSession(row) {
|
|
|
37191
37758
|
updatedAt: row.updated_at
|
|
37192
37759
|
};
|
|
37193
37760
|
}
|
|
37194
|
-
var SourceControlStorage = class extends
|
|
37761
|
+
var SourceControlStorage = class extends FactoryStorageDomain11 {
|
|
37195
37762
|
constructor() {
|
|
37196
37763
|
super("source-control");
|
|
37197
37764
|
}
|
|
@@ -37385,7 +37952,7 @@ var SourceControlStorage = class extends FactoryStorageDomain9 {
|
|
|
37385
37952
|
});
|
|
37386
37953
|
return toConnection(row);
|
|
37387
37954
|
} catch (error) {
|
|
37388
|
-
if (!(error instanceof
|
|
37955
|
+
if (!(error instanceof UniqueViolationError9)) throw error;
|
|
37389
37956
|
const row = await db().findOne(CONNECTIONS, {
|
|
37390
37957
|
factory_project_id: input.factoryProjectId,
|
|
37391
37958
|
integration_id: integrationId,
|
|
@@ -37514,7 +38081,7 @@ var SourceControlStorage = class extends FactoryStorageDomain9 {
|
|
|
37514
38081
|
});
|
|
37515
38082
|
return toSandbox(row);
|
|
37516
38083
|
} catch (error) {
|
|
37517
|
-
if (!(error instanceof
|
|
38084
|
+
if (!(error instanceof UniqueViolationError9)) throw error;
|
|
37518
38085
|
const row = await db().findOne(SANDBOXES, where);
|
|
37519
38086
|
if (!row) throw error;
|
|
37520
38087
|
return toSandbox(row);
|
|
@@ -37627,7 +38194,7 @@ var SourceControlStorage = class extends FactoryStorageDomain9 {
|
|
|
37627
38194
|
});
|
|
37628
38195
|
return toSession(row);
|
|
37629
38196
|
} catch (error) {
|
|
37630
|
-
if (!(error instanceof
|
|
38197
|
+
if (!(error instanceof UniqueViolationError9)) throw error;
|
|
37631
38198
|
const row = await db().findOne(SESSIONS, {
|
|
37632
38199
|
project_repository_id: input.projectRepositoryId,
|
|
37633
38200
|
user_id: input.userId,
|
|
@@ -37730,6 +38297,7 @@ var factorySkillExtension = {
|
|
|
37730
38297
|
function createWorkspaceFactory(options = {}) {
|
|
37731
38298
|
const { sandbox: sandboxConfig, github, fleet } = options;
|
|
37732
38299
|
const isLocalSandbox = sandboxConfig?.machine instanceof LocalSandbox;
|
|
38300
|
+
const githubTokenInjectors = /* @__PURE__ */ new Map();
|
|
37733
38301
|
return async ({ requestContext, mastra, skillExtension }) => {
|
|
37734
38302
|
const effectiveSkillExtension = skillExtension ?? factorySkillExtension;
|
|
37735
38303
|
const ctx = requestContext.get("controller");
|
|
@@ -37781,6 +38349,8 @@ function createWorkspaceFactory(options = {}) {
|
|
|
37781
38349
|
const existing = mastra?.getWorkspaceById(workspaceId);
|
|
37782
38350
|
if (existing) {
|
|
37783
38351
|
existing.setToolsConfig(MASTRACODE_WORKSPACE_TOOLS);
|
|
38352
|
+
const injectGithubToken3 = githubTokenInjectors.get(workspaceId);
|
|
38353
|
+
if (injectGithubToken3) registerGithubTokenInjector(requestContext, injectGithubToken3);
|
|
37784
38354
|
return existing;
|
|
37785
38355
|
}
|
|
37786
38356
|
} catch {
|
|
@@ -37811,6 +38381,14 @@ function createWorkspaceFactory(options = {}) {
|
|
|
37811
38381
|
repoFullName
|
|
37812
38382
|
});
|
|
37813
38383
|
if (projectRepository.setupCommand) await runWorktreeSetup(sandbox, workdir, projectRepository.setupCommand);
|
|
38384
|
+
const injectGithubToken2 = (freshToken) => {
|
|
38385
|
+
if (!sandbox.setEnvironmentVariable) {
|
|
38386
|
+
throw new Error("The active sandbox provider does not support runtime GitHub token refresh.");
|
|
38387
|
+
}
|
|
38388
|
+
sandbox.setEnvironmentVariable("GH_TOKEN", freshToken);
|
|
38389
|
+
};
|
|
38390
|
+
githubTokenInjectors.set(workspaceId, injectGithubToken2);
|
|
38391
|
+
registerGithubTokenInjector(requestContext, injectGithubToken2);
|
|
37814
38392
|
const filesystem = new SandboxFilesystem({ sandbox, workdir });
|
|
37815
38393
|
const projectSkillPaths = [path2.join(configDir, "skills"), ".claude/skills", ".agents/skills"];
|
|
37816
38394
|
const skillPaths = [...effectiveSkillExtension?.paths ?? [], ...projectSkillPaths];
|
|
@@ -37918,6 +38496,8 @@ var MastraFactory = class {
|
|
|
37918
38496
|
const workItemsStorage = storage.registerDomain(new WorkItemsStorage());
|
|
37919
38497
|
const modelCredentialsStorage = storage.registerDomain(new ModelCredentialsStorage());
|
|
37920
38498
|
const modelPacksStorage = storage.registerDomain(new ModelPacksStorage());
|
|
38499
|
+
const memorySettingsStorage = storage.registerDomain(new MemorySettingsStorage());
|
|
38500
|
+
const customProvidersStorage = storage.registerDomain(new CustomProvidersStorage());
|
|
37921
38501
|
const queueHealthStorage = storage.registerDomain(new QueueHealthStorage());
|
|
37922
38502
|
const integrationStorage = storage.registerDomain(new IntegrationStorage());
|
|
37923
38503
|
const factoryProjectsStorage = storage.registerDomain(new FactoryProjectsStorage());
|
|
@@ -37926,6 +38506,8 @@ var MastraFactory = class {
|
|
|
37926
38506
|
intake: intakeStorage,
|
|
37927
38507
|
modelCredentials: modelCredentialsStorage,
|
|
37928
38508
|
modelPacks: modelPacksStorage,
|
|
38509
|
+
memorySettings: memorySettingsStorage,
|
|
38510
|
+
customProviders: customProvidersStorage,
|
|
37929
38511
|
projects: factoryProjectsStorage,
|
|
37930
38512
|
queueHealth: queueHealthStorage,
|
|
37931
38513
|
workItems: workItemsStorage
|
|
@@ -37974,6 +38556,7 @@ var MastraFactory = class {
|
|
|
37974
38556
|
if (auth) {
|
|
37975
38557
|
registerTenantCredentialResolver(modelCredentialsStorage);
|
|
37976
38558
|
}
|
|
38559
|
+
registerCustomProvidersSource({ storage: customProvidersStorage, authEnabled: Boolean(auth) });
|
|
37977
38560
|
for (const integration of integrations) {
|
|
37978
38561
|
integration.initialize?.({
|
|
37979
38562
|
storage: integrationStorage.forIntegration(integration.id),
|
|
@@ -38038,6 +38621,9 @@ var MastraFactory = class {
|
|
|
38038
38621
|
fleet
|
|
38039
38622
|
}),
|
|
38040
38623
|
disableGithubSignals: true,
|
|
38624
|
+
// Memory settings live in the factory's `memory-settings` app table (per
|
|
38625
|
+
// org/user), so the host machine's TUI settings.json must not seed them.
|
|
38626
|
+
disableSettingsOmSeed: true,
|
|
38041
38627
|
storage: storage.getMastraStorage(),
|
|
38042
38628
|
...factoryProcessor ? { inputProcessors: [factoryProcessor] } : {},
|
|
38043
38629
|
...vector ? { vector } : {},
|
|
@@ -38146,12 +38732,25 @@ var MastraFactory = class {
|
|
|
38146
38732
|
const uiDist = resolveUiDistDir();
|
|
38147
38733
|
const spa = uiDist ? [createSpaStaticMiddleware(uiDist)] : [];
|
|
38148
38734
|
if (!auth) {
|
|
38149
|
-
return {
|
|
38735
|
+
return {
|
|
38736
|
+
middleware: [
|
|
38737
|
+
createCustomProvidersPrimer({ auth: routeAuth, storage: customProvidersStorage, authEnabled: false }),
|
|
38738
|
+
...spa
|
|
38739
|
+
],
|
|
38740
|
+
...cors,
|
|
38741
|
+
...onError
|
|
38742
|
+
};
|
|
38150
38743
|
}
|
|
38151
38744
|
return {
|
|
38745
|
+
auth,
|
|
38152
38746
|
middleware: [
|
|
38153
38747
|
createFactoryAuthGate(auth),
|
|
38154
38748
|
createTenantCredentialPrimer({ auth: routeAuth, credentials: modelCredentialsStorage }),
|
|
38749
|
+
createCustomProvidersPrimer({
|
|
38750
|
+
auth: routeAuth,
|
|
38751
|
+
storage: customProvidersStorage,
|
|
38752
|
+
authEnabled: Boolean(auth)
|
|
38753
|
+
}),
|
|
38155
38754
|
...spa
|
|
38156
38755
|
],
|
|
38157
38756
|
...cors,
|
|
@@ -38181,6 +38780,10 @@ var MastraFactory = class {
|
|
|
38181
38780
|
);
|
|
38182
38781
|
return {
|
|
38183
38782
|
...prepared.mastraArgs,
|
|
38783
|
+
// Same provider on `studio.auth` as on `server.auth` (buildServerConfig):
|
|
38784
|
+
// deployed factories must authenticate BOTH plain API callers and Studio
|
|
38785
|
+
// requests (`x-mastra-client-type: studio` routes to `studio.auth`).
|
|
38786
|
+
...auth ? { studio: { auth } } : {},
|
|
38184
38787
|
...integrationWorkers.length > 0 ? { workers: integrationWorkers } : {}
|
|
38185
38788
|
};
|
|
38186
38789
|
}
|