@massa-ai/mcp-client 1.51.0 → 1.53.0

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.
@@ -2174,17 +2174,11 @@ function detectRoute(platform, host) {
2174
2174
  if (route === "file")
2175
2175
  return { kind: "proceed" };
2176
2176
  if (route === "marketplace") {
2177
- if (host === "claude")
2177
+ if (host === "claude" || host === "codex")
2178
2178
  return { kind: "proceed" };
2179
- if (host === "codex") {
2180
- return {
2181
- kind: "refuse",
2182
- reason: "codex marketplace-route installs are refused (in-place bundle rewrite would dirty a checkout " + "and break the drift gate) \u2014 use the dev path: MASSA_AI_MODEL_PROFILE + regenerate."
2183
- };
2184
- }
2185
2179
  return {
2186
2180
  kind: "refuse",
2187
- reason: "claude/codex marketplace-route installs are refused (in-place bundle rewrite would dirty a checkout " + "and break the drift gate) \u2014 use the dev path: MASSA_AI_MODEL_PROFILE + regenerate."
2181
+ reason: "marketplace-route installs need an explicit, supported host before switching " + "(claude and codex proceed; no other host resolves a live write target yet) \u2014 " + "use the dev path: MASSA_AI_MODEL_PROFILE + regenerate."
2188
2182
  };
2189
2183
  }
2190
2184
  return {
@@ -2383,6 +2377,61 @@ var init_lock = __esm(() => {
2383
2377
  import fs5 from "fs";
2384
2378
  import os5 from "os";
2385
2379
  import path9 from "path";
2380
+ function splitPluginKey(pluginKey) {
2381
+ const at = pluginKey.indexOf("@");
2382
+ if (at === -1)
2383
+ return null;
2384
+ const pluginName = pluginKey.slice(0, at);
2385
+ const marketplaceName = pluginKey.slice(at + 1);
2386
+ if (!pluginName || !marketplaceName)
2387
+ return null;
2388
+ return { pluginName, marketplaceName };
2389
+ }
2390
+ function isContainedPath(root, candidate) {
2391
+ const rel = path9.relative(root, candidate);
2392
+ return rel === "" || !rel.startsWith("..") && !path9.isAbsolute(rel);
2393
+ }
2394
+ function resolveDirectorySourceRoot(targetHome, pluginKey) {
2395
+ const split = splitPluginKey(pluginKey);
2396
+ if (!split)
2397
+ return;
2398
+ const { pluginName, marketplaceName } = split;
2399
+ const knownMarketplacesPath = path9.join(targetHome, ".claude", "plugins", "known_marketplaces.json");
2400
+ let known;
2401
+ try {
2402
+ known = JSON.parse(fs5.readFileSync(knownMarketplacesPath, "utf8"));
2403
+ } catch {
2404
+ return;
2405
+ }
2406
+ const entry = known?.[marketplaceName];
2407
+ if (!entry || entry.source?.source !== "directory")
2408
+ return;
2409
+ const installLocation = entry.installLocation;
2410
+ if (!installLocation)
2411
+ return null;
2412
+ const manifestPath = path9.join(installLocation, ".claude-plugin", "marketplace.json");
2413
+ let manifest;
2414
+ try {
2415
+ manifest = JSON.parse(fs5.readFileSync(manifestPath, "utf8"));
2416
+ } catch {
2417
+ return null;
2418
+ }
2419
+ const plugin = manifest.plugins?.find((p) => p?.name === pluginName);
2420
+ const relSource = plugin?.source;
2421
+ if (!relSource)
2422
+ return null;
2423
+ const resolvedInstallLocation = path9.resolve(installLocation);
2424
+ const composed = path9.resolve(resolvedInstallLocation, relSource);
2425
+ if (!isContainedPath(resolvedInstallLocation, composed))
2426
+ return null;
2427
+ try {
2428
+ if (!fs5.existsSync(composed))
2429
+ return null;
2430
+ } catch {
2431
+ return null;
2432
+ }
2433
+ return composed;
2434
+ }
2386
2435
  function selectRecord(records) {
2387
2436
  if (records.length === 0)
2388
2437
  return;
@@ -2402,6 +2451,9 @@ function selectRecord(records) {
2402
2451
  function resolveClaudeMarketplaceRoot(opts = {}) {
2403
2452
  const targetHome = opts.targetHome ?? os5.homedir();
2404
2453
  const pluginKey = opts.pluginKey ?? DEFAULT_PLUGIN_KEY;
2454
+ const directoryResult = resolveDirectorySourceRoot(targetHome, pluginKey);
2455
+ if (directoryResult !== undefined)
2456
+ return directoryResult;
2405
2457
  const registryPath = path9.join(targetHome, ".claude", "plugins", "installed_plugins.json");
2406
2458
  let records;
2407
2459
  try {
@@ -2433,6 +2485,7 @@ import fs6 from "fs";
2433
2485
  import path10 from "path";
2434
2486
  import os6 from "os";
2435
2487
  import crypto4 from "crypto";
2488
+ import { execFileSync as execFileSync2 } from "child_process";
2436
2489
  function namedError3(name, message) {
2437
2490
  const err = new SwitchEngineError(message);
2438
2491
  err.name = name;
@@ -2511,6 +2564,46 @@ function matchesGlob(filename, glob) {
2511
2564
  const suffix = glob.slice(starIdx + 1);
2512
2565
  return filename.length >= prefix.length + suffix.length && filename.startsWith(prefix) && filename.endsWith(suffix);
2513
2566
  }
2567
+ function matchingFileNames(dir, glob) {
2568
+ return fs6.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && matchesGlob(e.name, glob)).map((e) => e.name);
2569
+ }
2570
+ function detectGitAvailability(dir) {
2571
+ try {
2572
+ const out = execFileSync2("git", ["-C", dir, "rev-parse", "--is-inside-work-tree"], {
2573
+ stdio: ["ignore", "pipe", "ignore"]
2574
+ });
2575
+ return out.toString().trim() === "true" ? "in-repo" : "not-a-repo";
2576
+ } catch (err) {
2577
+ return err.code === "ENOENT" ? "no-git" : "not-a-repo";
2578
+ }
2579
+ }
2580
+ function gitTrackedFileNames(dir, filenames) {
2581
+ if (filenames.length === 0)
2582
+ return new Set;
2583
+ try {
2584
+ const out = execFileSync2("git", ["-C", dir, "ls-files", "--", ...filenames], {
2585
+ stdio: ["ignore", "pipe", "ignore"]
2586
+ });
2587
+ return new Set(out.toString().split(`
2588
+ `).map((line) => line.trim()).filter(Boolean));
2589
+ } catch {
2590
+ return new Set;
2591
+ }
2592
+ }
2593
+ function checkTrackedPathGuard(activeDir, filenames) {
2594
+ if (filenames.length === 0 || !fs6.existsSync(activeDir))
2595
+ return GUARD_PASS;
2596
+ const availability = detectGitAvailability(activeDir);
2597
+ if (availability === "no-git")
2598
+ return GUARD_UNCHECKED;
2599
+ if (availability === "not-a-repo")
2600
+ return GUARD_PASS;
2601
+ const tracked = gitTrackedFileNames(activeDir, filenames);
2602
+ if (tracked.size === 0)
2603
+ return GUARD_PASS;
2604
+ const offending = filenames.find((name) => tracked.has(name));
2605
+ return { blocked: true, path: path10.join(activeDir, offending), unchecked: false };
2606
+ }
2514
2607
  function assertStateWritable(stateFilePath) {
2515
2608
  const dir = path10.dirname(stateFilePath);
2516
2609
  try {
@@ -2640,12 +2733,27 @@ function switchProfile(opts) {
2640
2733
  rows.push({ host: h.host, status: "switched" });
2641
2734
  continue;
2642
2735
  }
2736
+ const candidateNames = matchingFileNames(h.variantDir, h.layout.activeGlob);
2737
+ const guard = checkTrackedPathGuard(h.layout.activeDir, candidateNames);
2738
+ if (guard.blocked) {
2739
+ rows.push({
2740
+ host: h.host,
2741
+ status: "failed",
2742
+ reason: `refusing to write ${guard.path} \u2014 it is tracked by git and this switch would dirty the checkout`
2743
+ });
2744
+ continue;
2745
+ }
2643
2746
  try {
2644
2747
  const filesChanged = copyVariant(h.host, h.layout, h.variantDir);
2645
2748
  updatePlatform(stateFilePath, h.host, {
2646
2749
  modelProfile: { profile: opts.profile, switchedAt: new Date().toISOString() }
2647
2750
  });
2648
- rows.push({ host: h.host, status: "switched", filesChanged });
2751
+ rows.push({
2752
+ host: h.host,
2753
+ status: "switched",
2754
+ filesChanged,
2755
+ ...guard.unchecked ? { reason: "tracked-path guard could not verify (git unavailable) \u2014 proceeded unchecked" } : {}
2756
+ });
2649
2757
  } catch (err) {
2650
2758
  rows.push({ host: h.host, status: "failed", reason: err.message });
2651
2759
  }
@@ -2661,7 +2769,7 @@ function orderRows(universe, rows) {
2661
2769
  const byHost = new Map(rows.map((r) => [r.host, r]));
2662
2770
  return HOSTS.filter((h) => universe.includes(h) && byHost.has(h)).map((h) => byHost.get(h));
2663
2771
  }
2664
- var SwitchEngineError, UnknownProfileError = (profile, known) => namedError3("UnknownProfileError", `unknown profile "${profile}" \u2014 installed: ${known.length > 0 ? known.join(", ") : "none"}`), NoHostsDetectedError = () => namedError3("NoHostsDetectedError", "no installed hosts found");
2772
+ var SwitchEngineError, UnknownProfileError = (profile, known) => namedError3("UnknownProfileError", `unknown profile "${profile}" \u2014 installed: ${known.length > 0 ? known.join(", ") : "none"}`), NoHostsDetectedError = () => namedError3("NoHostsDetectedError", "no installed hosts found"), GUARD_PASS, GUARD_UNCHECKED;
2665
2773
  var init_engine = __esm(() => {
2666
2774
  init_hosts();
2667
2775
  init_state();
@@ -2673,6 +2781,8 @@ var init_engine = __esm(() => {
2673
2781
  this.name = "SwitchEngineError";
2674
2782
  }
2675
2783
  };
2784
+ GUARD_PASS = { blocked: false, unchecked: false };
2785
+ GUARD_UNCHECKED = { blocked: false, unchecked: true };
2676
2786
  });
2677
2787
 
2678
2788
  // ../../packages/shared/dist/profile-switch/report.js
@@ -122043,7 +122153,7 @@ var init_context_controller = __esm(() => {
122043
122153
  });
122044
122154
 
122045
122155
  // ../../packages/core/dist/services/executor/runtime.js
122046
- import { execFileSync as execFileSync2, execSync } from "child_process";
122156
+ import { execFileSync as execFileSync3, execSync } from "child_process";
122047
122157
  function commandExists(cmd) {
122048
122158
  try {
122049
122159
  const check2 = isWindows ? `where ${cmd}` : `command -v ${cmd}`;
@@ -122076,7 +122186,7 @@ function getVersion(cmd, args = ["--version"], deps) {
122076
122186
  timeout: 5000
122077
122187
  }).trim().split(/\r?\n/)[0];
122078
122188
  }
122079
- return execFileSync2(cmd, args, {
122189
+ return execFileSync3(cmd, args, {
122080
122190
  encoding: "utf-8",
122081
122191
  stdio: ["pipe", "pipe", "pipe"],
122082
122192
  timeout: 5000
@@ -122217,12 +122327,12 @@ var init_runtime = __esm(() => {
122217
122327
 
122218
122328
  // ../../packages/core/dist/services/executor/sandbox.js
122219
122329
  import { realpathSync as realpathSync2 } from "fs";
122220
- import { execFileSync as execFileSync3 } from "child_process";
122330
+ import { execFileSync as execFileSync4 } from "child_process";
122221
122331
  function isDockerAvailable() {
122222
122332
  if (_dockerAvailable !== null)
122223
122333
  return _dockerAvailable;
122224
122334
  try {
122225
- execFileSync3("docker", ["--version"], { stdio: "pipe", timeout: 5000 });
122335
+ execFileSync4("docker", ["--version"], { stdio: "pipe", timeout: 5000 });
122226
122336
  _dockerAvailable = true;
122227
122337
  } catch {
122228
122338
  _dockerAvailable = false;
@@ -122233,7 +122343,7 @@ function isSeatbeltAvailable() {
122233
122343
  if (_seatbeltAvailable !== null)
122234
122344
  return _seatbeltAvailable;
122235
122345
  try {
122236
- execFileSync3("sandbox-exec", ["--version"], { stdio: "pipe", timeout: 5000 });
122346
+ execFileSync4("sandbox-exec", ["--version"], { stdio: "pipe", timeout: 5000 });
122237
122347
  _seatbeltAvailable = true;
122238
122348
  } catch {
122239
122349
  _seatbeltAvailable = false;
@@ -122338,7 +122448,7 @@ var init_sandbox = __esm(() => {
122338
122448
  });
122339
122449
 
122340
122450
  // ../../packages/core/dist/services/executor/executor.js
122341
- import { spawn, execSync as execSync2, execFileSync as execFileSync4 } from "child_process";
122451
+ import { spawn, execSync as execSync2, execFileSync as execFileSync5 } from "child_process";
122342
122452
  import { mkdtempSync, writeFileSync as writeFileSync2, rmSync, realpathSync as realpathSync3 } from "fs";
122343
122453
  import { join as join3, resolve as resolve5, isAbsolute, relative as relative2 } from "path";
122344
122454
  import { tmpdir } from "os";
@@ -122541,7 +122651,7 @@ ${body}`;
122541
122651
  const binPath = srcPath.replace(/\.rs$/, isWin ? ".exe" : "");
122542
122652
  try {
122543
122653
  try {
122544
- execFileSync4("rustc", [srcPath, "-o", binPath], {
122654
+ execFileSync5("rustc", [srcPath, "-o", binPath], {
122545
122655
  cwd,
122546
122656
  timeout: Math.min(timeout, 60000),
122547
122657
  encoding: "utf-8",
@@ -123516,7 +123626,7 @@ var init_git_ref_validation = __esm(() => {
123516
123626
  });
123517
123627
 
123518
123628
  // ../../packages/core/dist/services/symbol/impact-analysis.js
123519
- import { execFileSync as execFileSync5 } from "child_process";
123629
+ import { execFileSync as execFileSync6 } from "child_process";
123520
123630
  function readBfsCteFlag() {
123521
123631
  try {
123522
123632
  return Boolean(config.get("impact")?.bfsCteEnabled);
@@ -123842,19 +123952,19 @@ function defaultDiffRunner(projectPath, scope, baseBranch, since) {
123842
123952
  let diffRange;
123843
123953
  if (since) {
123844
123954
  try {
123845
- ref = execFileSync5("git", ["-C", projectPath, "rev-parse", "--verify", `${since}^{commit}`], {
123955
+ ref = execFileSync6("git", ["-C", projectPath, "rev-parse", "--verify", `${since}^{commit}`], {
123846
123956
  cwd: projectPath,
123847
123957
  encoding: "utf-8",
123848
123958
  stdio: ["ignore", "pipe", "pipe"]
123849
123959
  }).trim();
123850
123960
  } catch {
123851
- ref = execFileSync5("git", ["-C", projectPath, "rev-list", "-1", `--before=${since}`, "HEAD"], {
123961
+ ref = execFileSync6("git", ["-C", projectPath, "rev-list", "-1", `--before=${since}`, "HEAD"], {
123852
123962
  cwd: projectPath,
123853
123963
  encoding: "utf-8",
123854
123964
  stdio: ["ignore", "pipe", "pipe"]
123855
123965
  }).trim();
123856
123966
  if (!ref) {
123857
- const emptyTree = execFileSync5("git", ["hash-object", "-t", "tree", "--stdin"], {
123967
+ const emptyTree = execFileSync6("git", ["hash-object", "-t", "tree", "--stdin"], {
123858
123968
  cwd: projectPath,
123859
123969
  encoding: "utf-8",
123860
123970
  input: "",
@@ -123866,7 +123976,7 @@ function defaultDiffRunner(projectPath, scope, baseBranch, since) {
123866
123976
  }
123867
123977
  args.push(diffRange ?? `${ref}...HEAD`);
123868
123978
  }
123869
- const out = execFileSync5("git", args, {
123979
+ const out = execFileSync6("git", args, {
123870
123980
  cwd: projectPath,
123871
123981
  encoding: "utf-8",
123872
123982
  stdio: ["ignore", "pipe", "pipe"],
@@ -123878,7 +123988,7 @@ function defaultDiffRunner(projectPath, scope, baseBranch, since) {
123878
123988
  let untrackedFiltered = 0;
123879
123989
  const merged = new Set(tracked);
123880
123990
  if (includeUntracked) {
123881
- const untracked = execFileSync5("git", ["-C", projectPath, "ls-files", "--others", "--exclude-standard"], {
123991
+ const untracked = execFileSync6("git", ["-C", projectPath, "ls-files", "--others", "--exclude-standard"], {
123882
123992
  cwd: projectPath,
123883
123993
  encoding: "utf-8",
123884
123994
  stdio: ["ignore", "pipe", "pipe"],
@@ -126760,6 +126870,85 @@ var init_scheduler = __esm(() => {
126760
126870
  };
126761
126871
  });
126762
126872
 
126873
+ // ../../packages/core/dist/data/proposal/proposal-payload-validation.js
126874
+ function isRecord(value) {
126875
+ return value !== null && typeof value === "object" && !Array.isArray(value);
126876
+ }
126877
+ function isStringArray(value) {
126878
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
126879
+ }
126880
+ function isString(value) {
126881
+ return typeof value === "string";
126882
+ }
126883
+ function isNumber(value) {
126884
+ return typeof value === "number";
126885
+ }
126886
+ function isValidProposalPayload(kind, value) {
126887
+ const rule = PROPOSAL_PAYLOAD_RULES[kind];
126888
+ if (!Object.keys(value).every((key) => rule.allowedKeys.includes(key)))
126889
+ return false;
126890
+ if (rule.requireNonEmpty && Object.keys(value).length === 0)
126891
+ return false;
126892
+ for (const [field, fieldRule] of Object.entries(rule.fields)) {
126893
+ const present = value[field] !== undefined;
126894
+ if (!present) {
126895
+ if (!fieldRule.optional)
126896
+ return false;
126897
+ continue;
126898
+ }
126899
+ if (!fieldRule.validate(value[field]))
126900
+ return false;
126901
+ }
126902
+ return true;
126903
+ }
126904
+ function assertValidProposalPayload(kind, value) {
126905
+ if (!isRecord(value)) {
126906
+ throw new ProposalPayloadValidationError(kind, `proposal payload must be an object for kind "${kind}"`);
126907
+ }
126908
+ if (!isValidProposalPayload(kind, value)) {
126909
+ throw new ProposalPayloadValidationError(kind, `proposal payload is invalid for kind "${kind}"`);
126910
+ }
126911
+ }
126912
+ var PROPOSAL_PAYLOAD_RULES, ProposalPayloadValidationError;
126913
+ var init_proposal_payload_validation = __esm(() => {
126914
+ PROPOSAL_PAYLOAD_RULES = {
126915
+ "memory.create": {
126916
+ allowedKeys: ["content", "type", "level", "importance", "tags"],
126917
+ fields: {
126918
+ content: { optional: false, validate: isString },
126919
+ type: { optional: true, validate: isString },
126920
+ level: { optional: true, validate: isNumber },
126921
+ importance: { optional: true, validate: isNumber },
126922
+ tags: { optional: true, validate: isStringArray }
126923
+ }
126924
+ },
126925
+ "memory.update": {
126926
+ allowedKeys: ["content", "importance", "tags"],
126927
+ requireNonEmpty: true,
126928
+ fields: {
126929
+ content: { optional: true, validate: isString },
126930
+ importance: { optional: true, validate: isNumber },
126931
+ tags: { optional: true, validate: isStringArray }
126932
+ }
126933
+ },
126934
+ "memory.tag": {
126935
+ allowedKeys: ["tags"],
126936
+ fields: {
126937
+ tags: { optional: false, validate: isStringArray }
126938
+ }
126939
+ }
126940
+ };
126941
+ ProposalPayloadValidationError = class ProposalPayloadValidationError extends Error {
126942
+ kind;
126943
+ statusCode = 400;
126944
+ constructor(kind, message) {
126945
+ super(message);
126946
+ this.kind = kind;
126947
+ this.name = "ProposalPayloadValidationError";
126948
+ }
126949
+ };
126950
+ });
126951
+
126763
126952
  // ../../packages/core/dist/data/proposal/proposal-contract.js
126764
126953
  class MemoryProposalStore {
126765
126954
  rows = [];
@@ -126783,26 +126972,53 @@ class MemoryProposalStore {
126783
126972
  row.decidedAt = decidedAt ?? Date.now();
126784
126973
  return structuredClone(row);
126785
126974
  }
126975
+ async create(input) {
126976
+ assertValidProposalPayload(input.kind, input.payload);
126977
+ const record2 = {
126978
+ id: input.id,
126979
+ projectId: input.projectId,
126980
+ kind: input.kind,
126981
+ targetMemoryId: input.targetMemoryId ?? null,
126982
+ payload: input.payload,
126983
+ rationale: input.rationale ?? "",
126984
+ status: "pending",
126985
+ createdAt: input.createdAt ?? Date.now(),
126986
+ decidedAt: null
126987
+ };
126988
+ this.rows.push(structuredClone(record2));
126989
+ return structuredClone(record2);
126990
+ }
126991
+ async update(id, patch) {
126992
+ const row = this.rows.find((item) => item.id === id);
126993
+ if (!row)
126994
+ return null;
126995
+ if (patch.payload !== undefined)
126996
+ assertValidProposalPayload(row.kind, patch.payload);
126997
+ if (patch.rationale !== undefined)
126998
+ row.rationale = patch.rationale;
126999
+ if (patch.payload !== undefined)
127000
+ row.payload = patch.payload;
127001
+ return structuredClone(row);
127002
+ }
127003
+ async delete(id) {
127004
+ const index = this.rows.findIndex((item) => item.id === id);
127005
+ if (index === -1)
127006
+ return null;
127007
+ this.rows.splice(index, 1);
127008
+ return id;
127009
+ }
126786
127010
  async journalMode() {
126787
127011
  return "memory";
126788
127012
  }
126789
127013
  }
126790
127014
  var PROPOSAL_STATUSES, PROPOSAL_KINDS;
126791
127015
  var init_proposal_contract = __esm(() => {
127016
+ init_proposal_payload_validation();
126792
127017
  PROPOSAL_STATUSES = ["pending", "approved", "rejected"];
126793
127018
  PROPOSAL_KINDS = ["memory.create", "memory.update", "memory.tag"];
126794
127019
  });
126795
127020
 
126796
127021
  // ../../packages/core/dist/data/proposal/proposal-repository-pg.js
126797
- function isRecord(value) {
126798
- return value !== null && typeof value === "object" && !Array.isArray(value);
126799
- }
126800
- function stringArray(value) {
126801
- return Array.isArray(value) && value.every((item) => typeof item === "string");
126802
- }
126803
- function validKeys(value, allowed) {
126804
- return Object.keys(value).every((key) => allowed.includes(key));
126805
- }
126806
127022
  function parsePayload(raw2, kind) {
126807
127023
  let value;
126808
127024
  try {
@@ -126813,15 +127029,7 @@ function parsePayload(raw2, kind) {
126813
127029
  if (!isRecord(value)) {
126814
127030
  throw storeCorruption("proposal.payload_json", new TypeError("expected object"));
126815
127031
  }
126816
- let valid = false;
126817
- if (kind === "memory.create") {
126818
- valid = validKeys(value, ["content", "type", "level", "importance", "tags"]) && typeof value.content === "string" && (value.type === undefined || typeof value.type === "string") && (value.level === undefined || typeof value.level === "number") && (value.importance === undefined || typeof value.importance === "number") && (value.tags === undefined || stringArray(value.tags));
126819
- } else if (kind === "memory.update") {
126820
- valid = validKeys(value, ["content", "importance", "tags"]) && Object.keys(value).length > 0 && (value.content === undefined || typeof value.content === "string") && (value.importance === undefined || typeof value.importance === "number") && (value.tags === undefined || stringArray(value.tags));
126821
- } else {
126822
- valid = validKeys(value, ["tags"]) && stringArray(value.tags);
126823
- }
126824
- if (!valid) {
127032
+ if (!isValidProposalPayload(kind, value)) {
126825
127033
  throw storeCorruption("proposal.payload_json", new TypeError("invalid proposal payload"));
126826
127034
  }
126827
127035
  return value;
@@ -126955,6 +127163,65 @@ class PgProposalStore {
126955
127163
  this.mirror.set(id, persisted);
126956
127164
  return structuredClone(persisted);
126957
127165
  }
127166
+ async create(input) {
127167
+ assertValidProposalPayload(input.kind, input.payload);
127168
+ const record2 = {
127169
+ id: input.id,
127170
+ projectId: input.projectId,
127171
+ kind: input.kind,
127172
+ targetMemoryId: input.targetMemoryId ?? null,
127173
+ payload: input.payload,
127174
+ rationale: input.rationale ?? "",
127175
+ status: "pending",
127176
+ createdAt: input.createdAt ?? Date.now(),
127177
+ decidedAt: null
127178
+ };
127179
+ await this.insert(record2);
127180
+ return record2;
127181
+ }
127182
+ async update(id, patch) {
127183
+ await this.ensureHydrated();
127184
+ const current = this.mirror.get(id);
127185
+ if (!current)
127186
+ return null;
127187
+ if (patch.payload !== undefined) {
127188
+ assertValidProposalPayload(current.kind, patch.payload);
127189
+ }
127190
+ const merged = {
127191
+ ...current,
127192
+ ...patch.rationale !== undefined ? { rationale: patch.rationale } : {},
127193
+ ...patch.payload !== undefined ? { payload: patch.payload } : {}
127194
+ };
127195
+ let rows;
127196
+ try {
127197
+ rows = await this.getClient().$queryRaw`
127198
+ UPDATE proposals
127199
+ SET rationale = ${merged.rationale}, payload_json = ${JSON.stringify(merged.payload)}
127200
+ WHERE id = ${id}
127201
+ RETURNING id, project_id, kind, target_memory_id, payload_json,
127202
+ rationale, status, created_at, decided_at`;
127203
+ } catch (error51) {
127204
+ throw searchBackendUnavailable("proposal_store", error51);
127205
+ }
127206
+ if (!rows[0])
127207
+ return null;
127208
+ const persisted = toRecord(rows[0]);
127209
+ this.mirror.set(id, persisted);
127210
+ return structuredClone(persisted);
127211
+ }
127212
+ async delete(id) {
127213
+ await this.ensureHydrated();
127214
+ let affected;
127215
+ try {
127216
+ affected = await this.getClient().$executeRaw`DELETE FROM proposals WHERE id = ${id}`;
127217
+ } catch (error51) {
127218
+ throw searchBackendUnavailable("proposal_store", error51);
127219
+ }
127220
+ if (affected === 0)
127221
+ return null;
127222
+ this.mirror.delete(id);
127223
+ return id;
127224
+ }
126958
127225
  async journalMode() {
126959
127226
  await this.ensureHydrated();
126960
127227
  return "postgres";
@@ -126971,6 +127238,7 @@ var init_proposal_repository_pg = __esm(() => {
126971
127238
  init_alias_resolver();
126972
127239
  init_search_diagnostics();
126973
127240
  init_proposal_contract();
127241
+ init_proposal_payload_validation();
126974
127242
  });
126975
127243
 
126976
127244
  // ../../packages/core/dist/data/proposal/proposal-repository.js