@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.
Files changed (85) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/factory.d.ts.map +1 -1
  3. package/dist/factory.js +812 -209
  4. package/dist/factory.js.map +1 -1
  5. package/dist/index.js +812 -209
  6. package/dist/index.js.map +1 -1
  7. package/dist/integrations/github/integration.d.ts +2 -2
  8. package/dist/integrations/github/integration.js +45 -11
  9. package/dist/integrations/github/integration.js.map +1 -1
  10. package/dist/integrations/github/provenance.js.map +1 -1
  11. package/dist/integrations/github/routes.d.ts.map +1 -1
  12. package/dist/integrations/github/routes.js +12 -9
  13. package/dist/integrations/github/routes.js.map +1 -1
  14. package/dist/integrations/github/sandbox.d.ts +1 -0
  15. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  16. package/dist/integrations/github/sandbox.js +2 -2
  17. package/dist/integrations/github/sandbox.js.map +1 -1
  18. package/dist/integrations/github/session-subscriptions.d.ts +3 -0
  19. package/dist/integrations/github/session-subscriptions.d.ts.map +1 -1
  20. package/dist/integrations/github/session-subscriptions.js +30 -0
  21. package/dist/integrations/github/session-subscriptions.js.map +1 -1
  22. package/dist/integrations/github/token-refresh.d.ts +6 -0
  23. package/dist/integrations/github/token-refresh.d.ts.map +1 -0
  24. package/dist/integrations/github/token-refresh.js +17 -0
  25. package/dist/integrations/github/token-refresh.js.map +1 -0
  26. package/dist/integrations/platform/github/event-worker.d.ts +2 -0
  27. package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
  28. package/dist/integrations/platform/github/event-worker.js +8 -0
  29. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  30. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  31. package/dist/integrations/platform/github/integration.js +52 -9
  32. package/dist/integrations/platform/github/integration.js.map +1 -1
  33. package/dist/routes/config.d.ts +16 -11
  34. package/dist/routes/config.d.ts.map +1 -1
  35. package/dist/routes/config.js +222 -109
  36. package/dist/routes/config.js.map +1 -1
  37. package/dist/routes/custom-provider-source.d.ts +52 -0
  38. package/dist/routes/custom-provider-source.d.ts.map +1 -0
  39. package/dist/routes/custom-provider-source.js +107 -0
  40. package/dist/routes/custom-provider-source.js.map +1 -0
  41. package/dist/routes/oauth.js +33 -1
  42. package/dist/routes/oauth.js.map +1 -1
  43. package/dist/routes/surface.d.ts +4 -0
  44. package/dist/routes/surface.d.ts.map +1 -1
  45. package/dist/routes/surface.js +282 -111
  46. package/dist/routes/surface.js.map +1 -1
  47. package/dist/routes/work-items.js.map +1 -1
  48. package/dist/rules/defaults.d.ts.map +1 -1
  49. package/dist/rules/defaults.js +8 -2
  50. package/dist/rules/defaults.js.map +1 -1
  51. package/dist/rules/dispatcher.js.map +1 -1
  52. package/dist/rules/github-service.d.ts +2 -0
  53. package/dist/rules/github-service.d.ts.map +1 -1
  54. package/dist/rules/github-service.js +15 -1
  55. package/dist/rules/github-service.js.map +1 -1
  56. package/dist/rules/index.js +8 -2
  57. package/dist/rules/index.js.map +1 -1
  58. package/dist/rules/linear-service.js.map +1 -1
  59. package/dist/rules/processor.js.map +1 -1
  60. package/dist/rules/tools.js.map +1 -1
  61. package/dist/rules/transition-service.js.map +1 -1
  62. package/dist/rules/types.d.ts +5 -0
  63. package/dist/rules/types.d.ts.map +1 -1
  64. package/dist/rules/types.js.map +1 -1
  65. package/dist/rules/validation.js.map +1 -1
  66. package/dist/sandbox/fleet.d.ts +3 -0
  67. package/dist/sandbox/fleet.d.ts.map +1 -1
  68. package/dist/sandbox/fleet.js +10 -3
  69. package/dist/sandbox/fleet.js.map +1 -1
  70. package/dist/spa-static.d.ts +4 -5
  71. package/dist/spa-static.d.ts.map +1 -1
  72. package/dist/spa-static.js +5 -2
  73. package/dist/spa-static.js.map +1 -1
  74. package/dist/storage/domains/custom-providers/base.d.ts +57 -0
  75. package/dist/storage/domains/custom-providers/base.d.ts.map +1 -0
  76. package/dist/storage/domains/custom-providers/base.js +150 -0
  77. package/dist/storage/domains/custom-providers/base.js.map +1 -0
  78. package/dist/storage/domains/memory-settings/base.d.ts +62 -0
  79. package/dist/storage/domains/memory-settings/base.d.ts.map +1 -0
  80. package/dist/storage/domains/memory-settings/base.js +111 -0
  81. package/dist/storage/domains/memory-settings/base.js.map +1 -0
  82. package/dist/workspace.d.ts.map +1 -1
  83. package/dist/workspace.js +17 -0
  84. package/dist/workspace.js.map +1 -1
  85. package/package.json +7 -6
@@ -11,8 +11,10 @@ import type { SandboxFleet } from '../sandbox/fleet.js';
11
11
  import type { StateSigner } from '../state-signing.js';
12
12
  import type { AuditEmitter } from '../storage/domains/audit/domain.js';
13
13
  import type { ModelCredentialsStorage } from '../storage/domains/credentials/base.js';
14
+ import type { CustomProvidersStorage } from '../storage/domains/custom-providers/base.js';
14
15
  import type { IntakeStorage } from '../storage/domains/intake/base.js';
15
16
  import type { IntegrationStorage } from '../storage/domains/integrations/base.js';
17
+ import type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';
16
18
  import type { ModelPacksStorage } from '../storage/domains/model-packs/base.js';
17
19
  import type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';
18
20
  import type { QueueHealthStorage } from '../storage/domains/queue-health/base.js';
@@ -44,6 +46,8 @@ export interface FactoryApiRoutesDeps {
44
46
  domains: {
45
47
  intake: IntakeStorage;
46
48
  modelCredentials: ModelCredentialsStorage;
49
+ memorySettings: MemorySettingsStorage;
50
+ customProviders: CustomProvidersStorage;
47
51
  modelPacks: ModelPacksStorage;
48
52
  projects: FactoryProjectsStorage;
49
53
  queueHealth: QueueHealthStorage;
@@ -1 +1 @@
1
- {"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../../src/routes/surface.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../../src/routes/surface.ts"],"names":[],"mappings":"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"}
@@ -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("SQLITE_CONSTRAINT");
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));
@@ -24849,6 +24881,11 @@ var FactoryGithubEventService = class {
24849
24881
  return results[0] ?? { status: "ignored" };
24850
24882
  }
24851
24883
  async #ingestProject(parsed, event, installationId, repositoryId, repositoryName, login, project) {
24884
+ const factoryProject = await this.options.projects.get({
24885
+ orgId: project.orgId,
24886
+ id: project.factoryProjectId
24887
+ });
24888
+ if (!factoryProject) return { status: "missing" };
24852
24889
  const issue = object(parsed.payload.issue);
24853
24890
  const pullRequest = object(parsed.payload.pull_request);
24854
24891
  const issueNumber = number(issue?.number);
@@ -24893,13 +24930,22 @@ var FactoryGithubEventService = class {
24893
24930
  } : {},
24894
24931
  event,
24895
24932
  deliveryId: parsed.deliveryId,
24933
+ factory: { createdAt: factoryProject.createdAt.toISOString() },
24896
24934
  repository: { id: repositoryId, fullName: repositoryName },
24897
- ...issueNumber && string(issue?.title) && string(issue?.html_url) ? { issue: { number: issueNumber, title: string(issue?.title), url: string(issue?.html_url) } } : {},
24935
+ ...issueNumber && string(issue?.title) && string(issue?.html_url) ? {
24936
+ issue: {
24937
+ number: issueNumber,
24938
+ title: string(issue?.title),
24939
+ url: string(issue?.html_url),
24940
+ ...string(issue?.created_at) ? { createdAt: string(issue?.created_at) } : {}
24941
+ }
24942
+ } : {},
24898
24943
  ...pullRequestNumber && string(pullRequest?.title) && string(pullRequest?.html_url) ? {
24899
24944
  pullRequest: {
24900
24945
  number: pullRequestNumber,
24901
24946
  title: string(pullRequest?.title),
24902
24947
  url: string(pullRequest?.html_url),
24948
+ ...string(pullRequest?.created_at) ? { createdAt: string(pullRequest?.created_at) } : {},
24903
24949
  state: string(pullRequest?.state) === "closed" ? "closed" : "open",
24904
24950
  merged: boolean(pullRequest?.merged) ?? false,
24905
24951
  headBranch: string(object(pullRequest?.head)?.ref) ?? "",
@@ -25396,19 +25442,9 @@ var FactoryTransitionService = class {
25396
25442
  };
25397
25443
 
25398
25444
  // src/routes/config.ts
25399
- import { removeCustomPackFromSettings } from "@mastra/code-sdk/onboarding/custom-packs";
25400
- import {
25401
- removeCustomProviderFromSettings,
25402
- upsertCustomProviderInSettings
25403
- } from "@mastra/code-sdk/onboarding/custom-providers";
25404
- import { applyOmRoleOverride, persistOmObserveAttachments } from "@mastra/code-sdk/onboarding/om-settings";
25445
+ import { DEFAULT_OM_MODEL_ID } from "@mastra/code-sdk/constants";
25405
25446
  import { getAvailableModePacks } from "@mastra/code-sdk/onboarding/packs";
25406
- import {
25407
- getCustomProviderId,
25408
- loadSettings,
25409
- saveSettings,
25410
- THREAD_ACTIVE_MODEL_PACK_ID_KEY
25411
- } from "@mastra/code-sdk/onboarding/settings";
25447
+ import { getCustomProviderId, THREAD_ACTIVE_MODEL_PACK_ID_KEY } from "@mastra/code-sdk/onboarding/settings";
25412
25448
  import { registerApiRoute } from "@mastra/core/server";
25413
25449
 
25414
25450
  // src/routes/provider-credentials.ts
@@ -25523,15 +25559,39 @@ async function listProviders({
25523
25559
  }
25524
25560
  return Array.from(seen.values()).sort((a, b) => a.provider.localeCompare(b.provider));
25525
25561
  }
25526
- function listCustomProviders() {
25527
- const settings = loadSettings();
25528
- return settings.customProviders.map((p) => ({
25529
- id: getCustomProviderId(p.name),
25530
- name: p.name,
25531
- url: p.url,
25532
- hasApiKey: Boolean(p.apiKey),
25533
- models: p.models
25534
- }));
25562
+ function toCustomProviderInfo(record) {
25563
+ return {
25564
+ id: record.providerId,
25565
+ name: record.name,
25566
+ url: record.url,
25567
+ hasApiKey: Boolean(record.apiKey),
25568
+ models: record.models
25569
+ };
25570
+ }
25571
+ async function resolveCustomProvidersContext({
25572
+ c,
25573
+ auth,
25574
+ customProviders
25575
+ }) {
25576
+ await auth.ensureUser(c);
25577
+ const tenant = auth.tenant(c);
25578
+ if (!tenant && auth.enabled()) return { response: c.json({ error: "unauthorized" }, 401) };
25579
+ if (customProviders) {
25580
+ try {
25581
+ await customProviders.ensureReady();
25582
+ return tenant ? { storage: customProviders, orgId: tenantOrgId(tenant), userId: tenant.userId } : { storage: customProviders, orgId: "local", userId: "local" };
25583
+ } catch {
25584
+ }
25585
+ }
25586
+ return {
25587
+ response: c.json(
25588
+ {
25589
+ error: "custom_providers_unavailable",
25590
+ message: "Custom provider storage is unavailable \u2014 the app database is not configured or failed to start."
25591
+ },
25592
+ 503
25593
+ )
25594
+ };
25535
25595
  }
25536
25596
  function parseCustomProviderBody(body) {
25537
25597
  if (!body || typeof body !== "object") return { error: "Invalid JSON body" };
@@ -25596,15 +25656,6 @@ async function buildProviderAccess({
25596
25656
  function canUseModelProvider(access, provider) {
25597
25657
  return Boolean(access[provider]);
25598
25658
  }
25599
- async function getTenantModelPacksStorage(modelPacks) {
25600
- if (!modelPacks) return void 0;
25601
- try {
25602
- await modelPacks.ensureReady();
25603
- } catch {
25604
- return void 0;
25605
- }
25606
- return modelPacks;
25607
- }
25608
25659
  async function resolvePackContext({
25609
25660
  c,
25610
25661
  auth,
@@ -25612,23 +25663,23 @@ async function resolvePackContext({
25612
25663
  }) {
25613
25664
  await auth.ensureUser(c);
25614
25665
  const tenant = auth.tenant(c);
25615
- if (!tenant) {
25616
- if (auth.enabled()) return { response: c.json({ error: "unauthorized" }, 401) };
25617
- return { mode: "local" };
25618
- }
25619
- const storage = await getTenantModelPacksStorage(modelPacks);
25620
- if (!storage) {
25621
- return {
25622
- response: c.json(
25623
- {
25624
- error: "model_packs_unavailable",
25625
- message: "Model pack storage is unavailable \u2014 the app database is not configured or failed to start."
25626
- },
25627
- 503
25628
- )
25629
- };
25666
+ if (!tenant && auth.enabled()) return { response: c.json({ error: "unauthorized" }, 401) };
25667
+ if (modelPacks) {
25668
+ try {
25669
+ await modelPacks.ensureReady();
25670
+ return tenant ? { storage: modelPacks, orgId: tenantOrgId(tenant), userId: tenant.userId } : { storage: modelPacks, orgId: "local", userId: "local" };
25671
+ } catch {
25672
+ }
25630
25673
  }
25631
- return { mode: "tenant", storage, orgId: tenantOrgId(tenant), userId: tenant.userId };
25674
+ return {
25675
+ response: c.json(
25676
+ {
25677
+ error: "model_packs_unavailable",
25678
+ message: "Model pack storage is unavailable \u2014 the app database is not configured or failed to start."
25679
+ },
25680
+ 503
25681
+ )
25682
+ };
25632
25683
  }
25633
25684
  function recordToModePack(record) {
25634
25685
  return { id: `custom:${record.id}`, name: record.name, description: "Saved custom pack", models: record.models };
@@ -25641,7 +25692,7 @@ async function listModelPacks({
25641
25692
  activePackId
25642
25693
  }) {
25643
25694
  const access = await buildProviderAccess({ controller, authStorage, tenantCredentials });
25644
- const packs = packContext.mode === "local" ? getAvailableModePacks(access, loadSettings().customModelPacks) : [
25695
+ const packs = [
25645
25696
  ...getAvailableModePacks(access),
25646
25697
  ...(await packContext.storage.list({ orgId: packContext.orgId })).map(recordToModePack)
25647
25698
  ];
@@ -25699,20 +25750,57 @@ function readOMConfig(session) {
25699
25750
  observeAttachments: observeAttachments === true || observeAttachments === false ? observeAttachments : "auto"
25700
25751
  };
25701
25752
  }
25702
- function persistOmThreshold({ role, value }) {
25703
- const settings = loadSettings();
25704
- if (role === "observation") settings.models.omObservationThreshold = value;
25705
- else settings.models.omReflectionThreshold = value;
25706
- saveSettings(settings);
25707
- }
25708
- function persistOmRoleOverride({
25709
- role,
25710
- modelId,
25711
- otherRoleCurrentModelId
25753
+ async function resolveMemorySettingsContext({
25754
+ c,
25755
+ auth,
25756
+ memorySettings
25712
25757
  }) {
25713
- const settings = loadSettings();
25714
- applyOmRoleOverride(settings, role, modelId, otherRoleCurrentModelId);
25715
- saveSettings(settings);
25758
+ await auth.ensureUser(c);
25759
+ const tenant = auth.tenant(c);
25760
+ if (!tenant && auth.enabled()) return { response: c.json({ error: "unauthorized" }, 401) };
25761
+ if (memorySettings) {
25762
+ try {
25763
+ await memorySettings.ensureReady();
25764
+ return tenant ? { storage: memorySettings, orgId: tenantOrgId(tenant), userId: tenant.userId } : { storage: memorySettings, orgId: "local", userId: "local" };
25765
+ } catch {
25766
+ }
25767
+ }
25768
+ return {
25769
+ response: c.json(
25770
+ {
25771
+ error: "memory_settings_unavailable",
25772
+ message: "Memory settings storage is unavailable \u2014 the app database is not configured or failed to start."
25773
+ },
25774
+ 503
25775
+ )
25776
+ };
25777
+ }
25778
+ async function persistMemorySettings(context, patch, fillIfUnset) {
25779
+ await context.storage.patch({ orgId: context.orgId, userId: context.userId, patch, fillIfUnset });
25780
+ }
25781
+ async function hydrateSessionMemorySettings(session, record) {
25782
+ for (const role of ["observer", "reflector"]) {
25783
+ const stored = role === "observer" ? record?.observerModelId : record?.reflectorModelId;
25784
+ const target = stored ?? DEFAULT_OM_MODEL_ID;
25785
+ if (session.om[role].modelId() !== target) {
25786
+ await session.om[role].switchModel({ modelId: target });
25787
+ }
25788
+ }
25789
+ const state = session.state.get() ?? {};
25790
+ const updates = {};
25791
+ const observationThreshold = record?.observationThreshold ?? DEFAULT_OBSERVATION_THRESHOLD;
25792
+ if (state.observationThreshold !== observationThreshold) {
25793
+ updates.observationThreshold = observationThreshold;
25794
+ }
25795
+ const reflectionThreshold = record?.reflectionThreshold ?? DEFAULT_REFLECTION_THRESHOLD;
25796
+ if (state.reflectionThreshold !== reflectionThreshold) {
25797
+ updates.reflectionThreshold = reflectionThreshold;
25798
+ }
25799
+ const observeAttachments = record?.observeAttachments ?? "auto";
25800
+ if ((state.observeAttachments ?? "auto") !== observeAttachments) {
25801
+ updates.observeAttachments = observeAttachments;
25802
+ }
25803
+ if (Object.keys(updates).length > 0) await session.state.set(updates);
25716
25804
  }
25717
25805
  var ConfigRoutes = class extends Route {
25718
25806
  routes() {
@@ -25720,6 +25808,8 @@ var ConfigRoutes = class extends Route {
25720
25808
  const { controller, authStorage, auth } = options;
25721
25809
  const onCredentialsChanged = options.onCredentialsChanged ?? (() => {
25722
25810
  });
25811
+ const onCustomProvidersChanged = options.onCustomProvidersChanged ?? (() => {
25812
+ });
25723
25813
  return [
25724
25814
  registerApiRoute("/web/config/providers", {
25725
25815
  method: "GET",
@@ -25811,14 +25901,22 @@ var ConfigRoutes = class extends Route {
25811
25901
  }
25812
25902
  }),
25813
25903
  // ── Custom providers (OpenAI-compatible endpoints) ──────────────────────
25814
- // Mirrors the TUI's /custom-providers command. Backed by GlobalSettings
25815
- // (settings.json), not session state these are user-global definitions.
25904
+ // Mirrors the TUI's /custom-providers command, but backed by the
25905
+ // `custom-providers` domain (org rows in tenant mode, a sentinel `local`
25906
+ // org in no-auth mode) — the server never reads settings.json for these.
25816
25907
  registerApiRoute("/web/config/custom-providers", {
25817
25908
  method: "GET",
25818
25909
  requiresAuth: false,
25819
- handler: (c) => {
25910
+ handler: async (c) => {
25911
+ const ctx = await resolveCustomProvidersContext({
25912
+ c: loose(c),
25913
+ auth,
25914
+ customProviders: options.customProviders
25915
+ });
25916
+ if ("response" in ctx) return ctx.response;
25820
25917
  try {
25821
- return c.json({ providers: listCustomProviders() });
25918
+ const records = await ctx.storage.list({ orgId: ctx.orgId });
25919
+ return c.json({ providers: records.map(toCustomProviderInfo) });
25822
25920
  } catch (error) {
25823
25921
  return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
25824
25922
  }
@@ -25828,6 +25926,12 @@ var ConfigRoutes = class extends Route {
25828
25926
  method: "POST",
25829
25927
  requiresAuth: false,
25830
25928
  handler: async (c) => {
25929
+ const ctx = await resolveCustomProvidersContext({
25930
+ c: loose(c),
25931
+ auth,
25932
+ customProviders: options.customProviders
25933
+ });
25934
+ if ("response" in ctx) return ctx.response;
25831
25935
  let body;
25832
25936
  try {
25833
25937
  body = await c.req.json();
@@ -25838,11 +25942,20 @@ var ConfigRoutes = class extends Route {
25838
25942
  if ("error" in parsed) return c.json({ error: parsed.error }, 400);
25839
25943
  const previousId = body && typeof body === "object" && typeof body.previousId === "string" ? body.previousId : void 0;
25840
25944
  try {
25841
- const settings = loadSettings();
25842
- upsertCustomProviderInSettings(settings, parsed, previousId);
25843
- saveSettings(settings);
25844
- const id = getCustomProviderId(parsed.name);
25845
- return c.json({ ok: true, provider: listCustomProviders().find((p) => p.id === id) });
25945
+ const record = await ctx.storage.upsert({
25946
+ orgId: ctx.orgId,
25947
+ userId: ctx.userId,
25948
+ input: {
25949
+ providerId: getCustomProviderId(parsed.name),
25950
+ name: parsed.name,
25951
+ url: parsed.url,
25952
+ apiKey: parsed.apiKey,
25953
+ models: parsed.models
25954
+ },
25955
+ previousProviderId: previousId
25956
+ });
25957
+ onCustomProvidersChanged({ orgId: ctx.orgId });
25958
+ return c.json({ ok: true, provider: toCustomProviderInfo(record) });
25846
25959
  } catch (error) {
25847
25960
  return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
25848
25961
  }
@@ -25851,12 +25964,17 @@ var ConfigRoutes = class extends Route {
25851
25964
  registerApiRoute("/web/config/custom-providers/:id", {
25852
25965
  method: "DELETE",
25853
25966
  requiresAuth: false,
25854
- handler: (c) => {
25967
+ handler: async (c) => {
25968
+ const ctx = await resolveCustomProvidersContext({
25969
+ c: loose(c),
25970
+ auth,
25971
+ customProviders: options.customProviders
25972
+ });
25973
+ if ("response" in ctx) return ctx.response;
25855
25974
  const id = c.req.param("id");
25856
25975
  try {
25857
- const settings = loadSettings();
25858
- removeCustomProviderFromSettings(settings, id);
25859
- saveSettings(settings);
25976
+ await ctx.storage.delete({ orgId: ctx.orgId, providerId: id });
25977
+ onCustomProvidersChanged({ orgId: ctx.orgId });
25860
25978
  return c.json({ ok: true });
25861
25979
  } catch (error) {
25862
25980
  return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
@@ -25885,8 +26003,30 @@ var ConfigRoutes = class extends Route {
25885
26003
  tenantCredentials
25886
26004
  })
25887
26005
  ]);
26006
+ 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 }));
26007
+ if (options.customProviders) {
26008
+ try {
26009
+ const ctx = await resolveCustomProvidersContext({
26010
+ c: loose(c),
26011
+ auth,
26012
+ customProviders: options.customProviders
26013
+ });
26014
+ if (!("response" in ctx)) {
26015
+ const known = new Set(catalog.map((m) => m.id));
26016
+ for (const record of await ctx.storage.list({ orgId: ctx.orgId })) {
26017
+ for (const model of record.models) {
26018
+ const id = `${record.providerId}/${model}`;
26019
+ if (known.has(id)) continue;
26020
+ known.add(id);
26021
+ catalog.push({ id, provider: record.providerId, modelName: model, hasApiKey: true });
26022
+ }
26023
+ }
26024
+ }
26025
+ } catch {
26026
+ }
26027
+ }
25888
26028
  return c.json({
25889
- models: models.filter((m) => canUseModelProvider(access, m.provider) && typeof m.id === "string").map((m) => ({ id: m.id, provider: m.provider, modelName: m.modelName, hasApiKey: true })).sort(
26029
+ models: catalog.sort(
25890
26030
  (a, b) => a.provider === b.provider ? a.id.localeCompare(b.id) : a.provider.localeCompare(b.provider)
25891
26031
  )
25892
26032
  });
@@ -25896,10 +26036,10 @@ var ConfigRoutes = class extends Route {
25896
26036
  }
25897
26037
  }),
25898
26038
  // ── Model packs ─────────────────────────────────────────────────────────
25899
- // Mirrors the TUI's /models-pack command. Custom-pack CRUD is DB-backed in
25900
- // tenant mode (model-packs storage domain, org-scoped) and settings.json in
25901
- // local mode; activation is session-scoped and resolves the session from
25902
- // the controller registry by resourceId.
26039
+ // Mirrors the TUI's /models-pack command. Custom-pack CRUD lives in the
26040
+ // model-packs storage domain (org-scoped, sentinel `local` org in no-auth
26041
+ // mode — never settings.json); activation is session-scoped and resolves
26042
+ // the session from the controller registry by resourceId.
25903
26043
  registerApiRoute("/web/config/model-packs", {
25904
26044
  method: "GET",
25905
26045
  requiresAuth: false,
@@ -25953,21 +26093,12 @@ var ConfigRoutes = class extends Route {
25953
26093
  return c.json({ error: "models.build, models.plan and models.fast are required" }, 400);
25954
26094
  }
25955
26095
  try {
25956
- if (packContext.mode === "tenant") {
25957
- const record = await packContext.storage.upsert({
25958
- orgId: packContext.orgId,
25959
- userId: packContext.userId,
25960
- input: { name, models: { build, plan, fast } }
25961
- });
25962
- return c.json({ ok: true, pack: recordToModePack(record) });
25963
- }
25964
- const settings = loadSettings();
25965
- const entry = { name, models: { build, plan, fast }, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
25966
- const idx = settings.customModelPacks.findIndex((p) => p.name === name);
25967
- if (idx >= 0) settings.customModelPacks[idx] = entry;
25968
- else settings.customModelPacks.push(entry);
25969
- saveSettings(settings);
25970
- return c.json({ ok: true, pack: { id: `custom:${name}`, name, models: { build, plan, fast } } });
26096
+ const record = await packContext.storage.upsert({
26097
+ orgId: packContext.orgId,
26098
+ userId: packContext.userId,
26099
+ input: { name, models: { build, plan, fast } }
26100
+ });
26101
+ return c.json({ ok: true, pack: recordToModePack(record) });
25971
26102
  } catch (error) {
25972
26103
  return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
25973
26104
  }
@@ -25981,15 +26112,9 @@ var ConfigRoutes = class extends Route {
25981
26112
  if ("response" in packContext) return packContext.response;
25982
26113
  const id = decodeURIComponent(c.req.param("id"));
25983
26114
  try {
25984
- if (packContext.mode === "tenant") {
25985
- const recordId = id.startsWith("custom:") ? id.slice("custom:".length) : id;
25986
- const deleted = await packContext.storage.delete({ orgId: packContext.orgId, id: recordId });
25987
- return deleted ? c.json({ ok: true }) : c.json({ error: `Unknown pack "${id}"` }, 404);
25988
- }
25989
- const settings = loadSettings();
25990
- removeCustomPackFromSettings(settings, id);
25991
- saveSettings(settings);
25992
- return c.json({ ok: true });
26115
+ const recordId = id.startsWith("custom:") ? id.slice("custom:".length) : id;
26116
+ const deleted = await packContext.storage.delete({ orgId: packContext.orgId, id: recordId });
26117
+ return deleted ? c.json({ ok: true }) : c.json({ error: `Unknown pack "${id}"` }, 404);
25993
26118
  } catch (error) {
25994
26119
  return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
25995
26120
  }
@@ -26036,8 +26161,10 @@ var ConfigRoutes = class extends Route {
26036
26161
  }),
26037
26162
  // ── Observational memory ──────────────────────────────────────────────────
26038
26163
  // Mirrors the TUI's /om command. All five knobs are session-scoped (resolved
26039
- // from the session, persisted to its state + thread setting) plus written to
26040
- // GlobalSettings so the choice survives restarts and stays in sync with the TUI.
26164
+ // from the session, persisted to its state + thread setting) and durably
26165
+ // stored in the per-(org, user) `memory-settings` app table never
26166
+ // settings.json. GET hydrates the session from the stored row first so the
26167
+ // DB, not the SDK's boot-time seed, is the source of truth.
26041
26168
  registerApiRoute("/web/config/om", {
26042
26169
  method: "GET",
26043
26170
  requiresAuth: false,
@@ -26045,9 +26172,17 @@ var ConfigRoutes = class extends Route {
26045
26172
  const resourceId = c.req.query("resourceId");
26046
26173
  const scope = c.req.query("scope") || void 0;
26047
26174
  if (!resourceId) return c.json({ error: "Missing required query param: resourceId" }, 400);
26175
+ const context = await resolveMemorySettingsContext({
26176
+ c: loose(c),
26177
+ auth,
26178
+ memorySettings: options.memorySettings
26179
+ });
26180
+ if ("response" in context) return context.response;
26048
26181
  try {
26049
26182
  const session = await controller.getSessionByResource?.(resourceId, scope);
26050
26183
  if (!session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
26184
+ const record = await context.storage.get({ orgId: context.orgId, userId: context.userId });
26185
+ await hydrateSessionMemorySettings(session, record);
26051
26186
  return c.json({ config: readOMConfig(session) });
26052
26187
  } catch (error) {
26053
26188
  return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
@@ -26073,13 +26208,24 @@ var ConfigRoutes = class extends Route {
26073
26208
  const modelId = typeof body.modelId === "string" ? body.modelId.trim() : "";
26074
26209
  if (!resourceId) return c.json({ error: "Missing required field: resourceId" }, 400);
26075
26210
  if (!modelId) return c.json({ error: "Missing required field: modelId" }, 400);
26211
+ const context = await resolveMemorySettingsContext({
26212
+ c: loose(c),
26213
+ auth,
26214
+ memorySettings: options.memorySettings
26215
+ });
26216
+ if ("response" in context) return context.response;
26076
26217
  try {
26077
26218
  const session = await controller.getSessionByResource?.(resourceId, scope);
26078
26219
  if (!session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
26079
26220
  const otherRole = role === "observer" ? session.om.reflector : session.om.observer;
26080
26221
  const otherRoleCurrentModelId = otherRole.modelId() ?? null;
26081
26222
  await session.om[role].switchModel({ modelId });
26082
- persistOmRoleOverride({ role, modelId, otherRoleCurrentModelId });
26223
+ const otherKey = role === "observer" ? "reflectorModelId" : "observerModelId";
26224
+ await persistMemorySettings(
26225
+ context,
26226
+ { [role === "observer" ? "observerModelId" : "reflectorModelId"]: modelId },
26227
+ otherRoleCurrentModelId ? { [otherKey]: otherRoleCurrentModelId } : void 0
26228
+ );
26083
26229
  return c.json({ ok: true, config: readOMConfig(session) });
26084
26230
  } catch (error) {
26085
26231
  return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
@@ -26104,19 +26250,27 @@ var ConfigRoutes = class extends Route {
26104
26250
  if (observation === void 0 && reflection === void 0) {
26105
26251
  return c.json({ error: "Provide observationThreshold and/or reflectionThreshold (positive numbers)" }, 400);
26106
26252
  }
26253
+ const context = await resolveMemorySettingsContext({
26254
+ c: loose(c),
26255
+ auth,
26256
+ memorySettings: options.memorySettings
26257
+ });
26258
+ if ("response" in context) return context.response;
26107
26259
  try {
26108
26260
  const session = await controller.getSessionByResource?.(resourceId, scope);
26109
26261
  if (!session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
26110
26262
  if (observation !== void 0) {
26111
26263
  await session.state.set({ observationThreshold: observation });
26112
26264
  await session.thread.setSetting({ key: "observationThreshold", value: observation });
26113
- persistOmThreshold({ role: "observation", value: observation });
26114
26265
  }
26115
26266
  if (reflection !== void 0) {
26116
26267
  await session.state.set({ reflectionThreshold: reflection });
26117
26268
  await session.thread.setSetting({ key: "reflectionThreshold", value: reflection });
26118
- persistOmThreshold({ role: "reflection", value: reflection });
26119
26269
  }
26270
+ await persistMemorySettings(context, {
26271
+ ...observation !== void 0 ? { observationThreshold: observation } : {},
26272
+ ...reflection !== void 0 ? { reflectionThreshold: reflection } : {}
26273
+ });
26120
26274
  return c.json({ ok: true, config: readOMConfig(session) });
26121
26275
  } catch (error) {
26122
26276
  return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
@@ -26141,12 +26295,18 @@ var ConfigRoutes = class extends Route {
26141
26295
  if (raw !== "auto" && raw !== true && raw !== false) {
26142
26296
  return c.json({ error: "value must be 'auto', true, or false" }, 400);
26143
26297
  }
26298
+ const context = await resolveMemorySettingsContext({
26299
+ c: loose(c),
26300
+ auth,
26301
+ memorySettings: options.memorySettings
26302
+ });
26303
+ if ("response" in context) return context.response;
26144
26304
  try {
26145
26305
  const session = await controller.getSessionByResource?.(resourceId, scope);
26146
26306
  if (!session) return c.json({ error: `No session for resourceId "${resourceId}"` }, 404);
26147
26307
  await session.state.set({ observeAttachments: value });
26148
26308
  await session.thread.setSetting({ key: "observeAttachments", value });
26149
- persistOmObserveAttachments(value);
26309
+ await persistMemorySettings(context, { observeAttachments: value });
26150
26310
  return c.json({ ok: true, config: readOMConfig(session) });
26151
26311
  } catch (error) {
26152
26312
  return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
@@ -26157,6 +26317,13 @@ var ConfigRoutes = class extends Route {
26157
26317
  }
26158
26318
  };
26159
26319
 
26320
+ // src/routes/custom-provider-source.ts
26321
+ import { setCustomProvidersSource } from "@mastra/code-sdk/agents/custom-provider-source";
26322
+ var orgSnapshots = /* @__PURE__ */ new Map();
26323
+ function invalidateCustomProvidersSnapshots(tenant) {
26324
+ orgSnapshots.delete(tenant.orgId);
26325
+ }
26326
+
26160
26327
  // src/routes/fs.ts
26161
26328
  import { lstat, open, readdir, realpath, stat } from "fs/promises";
26162
26329
  import { homedir } from "os";
@@ -28413,6 +28580,7 @@ function assembleFactoryApiRoutes(deps) {
28413
28580
  github: githubIntegration,
28414
28581
  sourceControl: githubStorage,
28415
28582
  integrationStorage: deps.integrationStorage.forIntegration("github"),
28583
+ projects: deps.domains.projects,
28416
28584
  storage: workItems,
28417
28585
  rules: deps.rules
28418
28586
  }) : void 0;
@@ -28460,7 +28628,10 @@ function assembleFactoryApiRoutes(deps) {
28460
28628
  authStorage: deps.authStorage,
28461
28629
  modelCredentials: deps.domains.modelCredentials,
28462
28630
  modelPacks: deps.domains.modelPacks,
28463
- onCredentialsChanged: invalidateTenantCredentialSnapshots
28631
+ memorySettings: deps.domains.memorySettings,
28632
+ customProviders: deps.domains.customProviders,
28633
+ onCredentialsChanged: invalidateTenantCredentialSnapshots,
28634
+ onCustomProvidersChanged: invalidateCustomProvidersSnapshots
28464
28635
  }).routes(),
28465
28636
  ...new OAuthRoutes({
28466
28637
  auth: deps.auth,