@kylewadegrove/cutline-mcp-cli 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -87,8 +87,8 @@ async function identifyTrialUser(attrs) {
87
87
  created_at: Math.floor(Date.now() / 1e3)
88
88
  });
89
89
  console.log(`[Customer.io] Identified trial user: ${attrs.email}`);
90
- } catch (error5) {
91
- console.error("[Customer.io] Error identifying trial user:", error5);
90
+ } catch (error6) {
91
+ console.error("[Customer.io] Error identifying trial user:", error6);
92
92
  }
93
93
  }
94
94
  async function trackTrialEvent(email, event, data) {
@@ -101,8 +101,8 @@ async function trackTrialEvent(email, event, data) {
101
101
  data: { ...data, timestamp: Math.floor(Date.now() / 1e3) }
102
102
  });
103
103
  console.log(`[Customer.io] Tracked ${event} for ${email}`);
104
- } catch (error5) {
105
- console.error(`[Customer.io] Error tracking ${event}:`, error5);
104
+ } catch (error6) {
105
+ console.error(`[Customer.io] Error tracking ${event}:`, error6);
106
106
  }
107
107
  }
108
108
  var rateLimitStore = /* @__PURE__ */ new Map();
@@ -908,8 +908,8 @@ var stripeWebhooks = onRequest4({ cors: true, timeoutSeconds: 30, memory: "512Mi
908
908
  await processStripeEvent(event, stripe);
909
909
  audit({ eventType: "data.updated", resourceType: "stripe_webhook", resourceId: event.id, data: { type: event.type } });
910
910
  res.status(200).json({ success: true });
911
- } catch (error5) {
912
- console.error(`[Stripe] Webhook handling failed for ${event.type}:`, error5);
911
+ } catch (error6) {
912
+ console.error(`[Stripe] Webhook handling failed for ${event.type}:`, error6);
913
913
  audit({ eventType: "pipeline.failed", resourceType: "stripe_webhook", resourceId: event.id, success: false, error: "Webhook handling failed", data: { type: event.type } });
914
914
  res.status(500).json({ error: "Webhook handling failed" });
915
915
  }
@@ -5737,9 +5737,9 @@ Respond as ${personaContext.persona.name} would. Be authentic, specific, and tru
5737
5737
  confidence: parsed.confidence,
5738
5738
  reasoning: parsed.reasoning
5739
5739
  };
5740
- } catch (error5) {
5741
- console.error("[persona-agent] Error generating response:", error5);
5742
- throw new Error(`Failed to generate persona response: ${error5.message}`);
5740
+ } catch (error6) {
5741
+ console.error("[persona-agent] Error generating response:", error6);
5742
+ throw new Error(`Failed to generate persona response: ${error6.message}`);
5743
5743
  }
5744
5744
  }
5745
5745
 
@@ -6602,8 +6602,8 @@ async function identifyVibekitUser(attrs) {
6602
6602
  created_at: Math.floor(Date.now() / 1e3)
6603
6603
  });
6604
6604
  console.log(`[Customer.io] Identified vibekit user: ${attrs.email}`);
6605
- } catch (error5) {
6606
- console.error("[Customer.io] Error identifying vibekit user:", error5);
6605
+ } catch (error6) {
6606
+ console.error("[Customer.io] Error identifying vibekit user:", error6);
6607
6607
  }
6608
6608
  }
6609
6609
  async function trackVibekitEvent(email, event, data) {
@@ -6616,8 +6616,8 @@ async function trackVibekitEvent(email, event, data) {
6616
6616
  data: { ...data, timestamp: Math.floor(Date.now() / 1e3) }
6617
6617
  });
6618
6618
  console.log(`[Customer.io] Tracked ${event} for ${email}`);
6619
- } catch (error5) {
6620
- console.error(`[Customer.io] Error tracking ${event}:`, error5);
6619
+ } catch (error6) {
6620
+ console.error(`[Customer.io] Error tracking ${event}:`, error6);
6621
6621
  }
6622
6622
  }
6623
6623
  var ALLOWED_ORIGINS = [
@@ -7747,8 +7747,8 @@ Respond conversationally while advancing the discovery. Put structured data in a
7747
7747
  response.artifacts = artifacts;
7748
7748
  }
7749
7749
  return response;
7750
- } catch (error5) {
7751
- console.error("[consulting-discovery-agent] Error:", error5);
7750
+ } catch (error6) {
7751
+ console.error("[consulting-discovery-agent] Error:", error6);
7752
7752
  return {
7753
7753
  content: getDegenerateFallback2(context.currentAct, context),
7754
7754
  wasFallback: true
@@ -9504,18 +9504,18 @@ var personaAgent = onRequest17({ cors: true, timeoutSeconds: 60, memory: "512MiB
9504
9504
  confidence: response.confidence,
9505
9505
  reasoning: response.reasoning
9506
9506
  });
9507
- } catch (error5) {
9508
- console.error("[persona-agent] Error:", error5);
9507
+ } catch (error6) {
9508
+ console.error("[persona-agent] Error:", error6);
9509
9509
  res.status(500).json({
9510
9510
  error: "Failed to generate persona response",
9511
- message: error5?.message || "Unknown error"
9511
+ message: error6?.message || "Unknown error"
9512
9512
  });
9513
9513
  }
9514
- } catch (error5) {
9515
- console.error("[persona-agent] Request error:", error5);
9514
+ } catch (error6) {
9515
+ console.error("[persona-agent] Request error:", error6);
9516
9516
  res.status(500).json({
9517
9517
  error: "Internal server error",
9518
- message: error5?.message || "Unknown error"
9518
+ message: error6?.message || "Unknown error"
9519
9519
  });
9520
9520
  }
9521
9521
  });
@@ -9604,18 +9604,18 @@ var mcpGenerateTokenG2 = onCall({ timeoutSeconds: 60 }, async (request) => {
9604
9604
  deviceId,
9605
9605
  email: auth?.token.email
9606
9606
  };
9607
- } catch (error5) {
9607
+ } catch (error6) {
9608
9608
  logger.error("MCP token generation failed", {
9609
9609
  uid,
9610
9610
  deviceId,
9611
9611
  error: {
9612
- message: error5.message,
9613
- code: error5.code
9612
+ message: error6.message,
9613
+ code: error6.code
9614
9614
  }
9615
9615
  });
9616
9616
  audit({ eventType: "security.anomaly", userId: uid, resourceType: "mcp_token", resourceId: deviceId, success: false, error: "Token generation failed" });
9617
- if (error5 instanceof HttpsError2) {
9618
- throw error5;
9617
+ if (error6 instanceof HttpsError2) {
9618
+ throw error6;
9619
9619
  }
9620
9620
  throw new HttpsError2("internal", "Failed to generate MCP token");
9621
9621
  }
@@ -9670,13 +9670,13 @@ var mcpSubscriptionStatus = onRequest18({
9670
9670
  };
9671
9671
  logger2.info("Subscription status retrieved", { uid, status: response.status });
9672
9672
  res.json(response);
9673
- } catch (error5) {
9674
- logger2.error("Failed to get subscription status", { error: error5.message });
9675
- if (error5.code === "auth/id-token-expired") {
9673
+ } catch (error6) {
9674
+ logger2.error("Failed to get subscription status", { error: error6.message });
9675
+ if (error6.code === "auth/id-token-expired") {
9676
9676
  res.status(401).json({ error: "Token expired" });
9677
9677
  return;
9678
9678
  }
9679
- if (error5.code === "auth/argument-error" || error5.code === "auth/invalid-id-token") {
9679
+ if (error6.code === "auth/argument-error" || error6.code === "auth/invalid-id-token") {
9680
9680
  res.status(401).json({ error: "Invalid token" });
9681
9681
  return;
9682
9682
  }
@@ -9716,13 +9716,13 @@ var mcpListProducts = onRequest19({ timeoutSeconds: 30, cors: true }, async (req
9716
9716
  };
9717
9717
  });
9718
9718
  res.json({ products });
9719
- } catch (error5) {
9720
- logger3.error("Failed to list products", { error: error5.message });
9721
- if (error5.code === "auth/id-token-expired") {
9719
+ } catch (error6) {
9720
+ logger3.error("Failed to list products", { error: error6.message });
9721
+ if (error6.code === "auth/id-token-expired") {
9722
9722
  res.status(401).json({ error: "Token expired" });
9723
9723
  return;
9724
9724
  }
9725
- if (error5.code === "auth/argument-error" || error5.code === "auth/invalid-id-token") {
9725
+ if (error6.code === "auth/argument-error" || error6.code === "auth/invalid-id-token") {
9726
9726
  res.status(401).json({ error: "Invalid token" });
9727
9727
  return;
9728
9728
  }
@@ -9730,11 +9730,433 @@ var mcpListProducts = onRequest19({ timeoutSeconds: 30, cors: true }, async (req
9730
9730
  }
9731
9731
  });
9732
9732
 
9733
+ // ../lib/mcp/data-proxy.js
9734
+ import { onRequest as onRequest20 } from "firebase-functions/v2/https";
9735
+ import * as logger4 from "firebase-functions/logger";
9736
+ import admin17 from "firebase-admin";
9737
+ var handlers = {};
9738
+ function register(action, handler) {
9739
+ handlers[action] = handler;
9740
+ }
9741
+ register("premortem.list", async (uid, params) => {
9742
+ const db = admin17.firestore();
9743
+ let query = db.collection("premortem_jobs").where("uid", "==", uid).orderBy("createdAt", "desc");
9744
+ if (params.status) {
9745
+ query = query.where("status", "==", params.status);
9746
+ }
9747
+ if (params.limit) {
9748
+ query = query.limit(Math.min(params.limit, 100));
9749
+ }
9750
+ const snap = await query.get();
9751
+ return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
9752
+ });
9753
+ register("premortem.get", async (uid, params) => {
9754
+ const db = admin17.firestore();
9755
+ const doc = await db.collection("premortem_jobs").doc(params.id).get();
9756
+ if (!doc.exists)
9757
+ return { doc: null };
9758
+ const data = doc.data();
9759
+ if (data?.uid !== uid)
9760
+ return { doc: null };
9761
+ return { doc: { id: doc.id, ...data } };
9762
+ });
9763
+ register("premortem.create", async (uid, params) => {
9764
+ const db = admin17.firestore();
9765
+ const ref = params.id ? db.collection("premortem_jobs").doc(params.id) : db.collection("premortem_jobs").doc();
9766
+ await ref.set({ ...params.data, uid, createdAt: admin17.firestore.FieldValue.serverTimestamp() });
9767
+ return { id: ref.id };
9768
+ });
9769
+ register("premortem.update", async (uid, params) => {
9770
+ const db = admin17.firestore();
9771
+ const ref = db.collection("premortem_jobs").doc(params.id);
9772
+ const doc = await ref.get();
9773
+ if (!doc.exists || doc.data()?.uid !== uid) {
9774
+ throw new Error("Not found or not authorized");
9775
+ }
9776
+ await ref.update(params.data);
9777
+ return { ok: true };
9778
+ });
9779
+ register("premortem.getIdea", async (uid, params) => {
9780
+ const db = admin17.firestore();
9781
+ const doc = await db.collection("idea_reports").doc(params.id).get();
9782
+ if (!doc.exists)
9783
+ return { doc: null };
9784
+ return { doc: { id: doc.id, ...doc.data() } };
9785
+ });
9786
+ register("chat.save", async (uid, params) => {
9787
+ const db = admin17.firestore();
9788
+ const ref = db.collection("premortem_chats").doc(params.id);
9789
+ await ref.set({ ...params.data, uid, updatedAt: admin17.firestore.FieldValue.serverTimestamp() });
9790
+ return { id: ref.id };
9791
+ });
9792
+ register("chat.get", async (uid, params) => {
9793
+ const db = admin17.firestore();
9794
+ const doc = await db.collection("premortem_chats").doc(params.id).get();
9795
+ if (!doc.exists)
9796
+ return { doc: null };
9797
+ const data = doc.data();
9798
+ if (data?.uid !== uid)
9799
+ return { doc: null };
9800
+ return { doc: { id: doc.id, ...data } };
9801
+ });
9802
+ register("chat.update", async (uid, params) => {
9803
+ const db = admin17.firestore();
9804
+ const ref = db.collection("premortem_chats").doc(params.id);
9805
+ const doc = await ref.get();
9806
+ if (!doc.exists || doc.data()?.uid !== uid) {
9807
+ throw new Error("Not found or not authorized");
9808
+ }
9809
+ await ref.update(params.data);
9810
+ return { ok: true };
9811
+ });
9812
+ register("exploration.create", async (uid, params) => {
9813
+ const db = admin17.firestore();
9814
+ const collection = params.collection || "exploration_sessions";
9815
+ const ref = db.collection(collection).doc(params.id);
9816
+ await ref.set({ ...params.data, uid, createdAt: admin17.firestore.FieldValue.serverTimestamp() });
9817
+ return { id: ref.id };
9818
+ });
9819
+ register("exploration.get", async (uid, params) => {
9820
+ const db = admin17.firestore();
9821
+ const collection = params.collection || "exploration_sessions";
9822
+ const doc = await db.collection(collection).doc(params.id).get();
9823
+ if (!doc.exists)
9824
+ return { doc: null };
9825
+ const data = doc.data();
9826
+ if (data?.uid !== uid)
9827
+ return { doc: null };
9828
+ return { doc: { id: doc.id, ...data } };
9829
+ });
9830
+ register("exploration.update", async (uid, params) => {
9831
+ const db = admin17.firestore();
9832
+ const collection = params.collection || "exploration_sessions";
9833
+ const ref = db.collection(collection).doc(params.id);
9834
+ const doc = await ref.get();
9835
+ if (!doc.exists || doc.data()?.uid !== uid) {
9836
+ throw new Error("Not found or not authorized");
9837
+ }
9838
+ await ref.update(params.data);
9839
+ return { ok: true };
9840
+ });
9841
+ register("exploration.list", async (uid, params) => {
9842
+ const db = admin17.firestore();
9843
+ const collection = params.collection || "exploration_sessions";
9844
+ const limit = Math.min(params.limit || 20, 100);
9845
+ const snap = await db.collection(collection).where("uid", "==", uid).orderBy("createdAt", "desc").limit(limit).get();
9846
+ return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
9847
+ });
9848
+ function graphCol(productId, sub) {
9849
+ return admin17.firestore().collection("context_graph").doc(productId).collection(sub);
9850
+ }
9851
+ register("graph.getEntities", async (_uid, params) => {
9852
+ const snap = await graphCol(params.productId, "entities").get();
9853
+ return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
9854
+ });
9855
+ register("graph.upsertEntities", async (_uid, params) => {
9856
+ const col = graphCol(params.productId, "entities");
9857
+ const batch = admin17.firestore().batch();
9858
+ if (params.deleteIds?.length) {
9859
+ for (const id of params.deleteIds) {
9860
+ batch.delete(col.doc(id));
9861
+ }
9862
+ }
9863
+ if (params.entities?.length) {
9864
+ for (const entity of params.entities) {
9865
+ const id = entity.id || col.doc().id;
9866
+ batch.set(col.doc(id), entity);
9867
+ }
9868
+ }
9869
+ await batch.commit();
9870
+ return { ok: true };
9871
+ });
9872
+ register("graph.getEdges", async (_uid, params) => {
9873
+ const snap = await graphCol(params.productId, "edges").get();
9874
+ return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
9875
+ });
9876
+ register("graph.upsertEdges", async (_uid, params) => {
9877
+ const col = graphCol(params.productId, "edges");
9878
+ const batch = admin17.firestore().batch();
9879
+ if (params.deleteIds?.length) {
9880
+ for (const id of params.deleteIds) {
9881
+ batch.delete(col.doc(id));
9882
+ }
9883
+ }
9884
+ if (params.edges?.length) {
9885
+ for (const edge of params.edges) {
9886
+ const id = edge.id || col.doc().id;
9887
+ batch.set(col.doc(id), edge);
9888
+ }
9889
+ }
9890
+ await batch.commit();
9891
+ return { ok: true };
9892
+ });
9893
+ register("graph.getBindings", async (_uid, params) => {
9894
+ const col = graphCol(params.productId, "bindings");
9895
+ let query = col;
9896
+ if (params.entityId) {
9897
+ query = col.where("entityId", "==", params.entityId);
9898
+ }
9899
+ const snap = await query.get();
9900
+ return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
9901
+ });
9902
+ register("graph.upsertBindings", async (_uid, params) => {
9903
+ const col = graphCol(params.productId, "bindings");
9904
+ const batch = admin17.firestore().batch();
9905
+ if (params.deleteIds?.length) {
9906
+ for (const id of params.deleteIds) {
9907
+ batch.delete(col.doc(id));
9908
+ }
9909
+ }
9910
+ if (params.bindings?.length) {
9911
+ for (const binding of params.bindings) {
9912
+ const id = binding.id || col.doc().id;
9913
+ batch.set(col.doc(id), binding, { merge: true });
9914
+ }
9915
+ }
9916
+ await batch.commit();
9917
+ return { ok: true };
9918
+ });
9919
+ register("graph.getNodes", async (_uid, params) => {
9920
+ const col = graphCol(params.productId, "nodes");
9921
+ let query = col;
9922
+ if (params.categories?.length) {
9923
+ query = col.where("category", "in", params.categories);
9924
+ }
9925
+ if (params.sourceType) {
9926
+ query = col.where("source_type", "==", params.sourceType);
9927
+ }
9928
+ if (params.light) {
9929
+ query = query.select("id", "category", "title", "severity", "source_type", "tags");
9930
+ }
9931
+ const snap = await query.get();
9932
+ return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
9933
+ });
9934
+ register("graph.upsertNodes", async (_uid, params) => {
9935
+ const col = graphCol(params.productId, "nodes");
9936
+ const batch = admin17.firestore().batch();
9937
+ if (params.deleteIds?.length) {
9938
+ for (const id of params.deleteIds) {
9939
+ batch.delete(col.doc(id));
9940
+ }
9941
+ }
9942
+ if (params.nodes?.length) {
9943
+ for (const node of params.nodes) {
9944
+ const id = node.id || col.doc().id;
9945
+ batch.set(col.doc(id), node);
9946
+ }
9947
+ }
9948
+ await batch.commit();
9949
+ return { ok: true };
9950
+ });
9951
+ register("graph.getTestCases", async (_uid, params) => {
9952
+ const col = graphCol(params.productId, "test_cases");
9953
+ let query = col;
9954
+ if (params.entityId) {
9955
+ query = col.where("entityId", "==", params.entityId);
9956
+ }
9957
+ const snap = await query.get();
9958
+ return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
9959
+ });
9960
+ register("graph.addTestCases", async (_uid, params) => {
9961
+ const col = graphCol(params.productId, "test_cases");
9962
+ const batch = admin17.firestore().batch();
9963
+ for (const tc of params.testCases || []) {
9964
+ const id = tc.id || col.doc().id;
9965
+ batch.set(col.doc(id), tc, { merge: true });
9966
+ }
9967
+ await batch.commit();
9968
+ return { ok: true };
9969
+ });
9970
+ register("graph.getMeta", async (_uid, params) => {
9971
+ const doc = await admin17.firestore().collection("context_graph").doc(params.productId).collection("_meta").doc("graph").get();
9972
+ return { doc: doc.exists ? { id: doc.id, ...doc.data() } : null };
9973
+ });
9974
+ register("graph.updateMeta", async (_uid, params) => {
9975
+ const ref = admin17.firestore().collection("context_graph").doc(params.productId).collection("_meta").doc("graph");
9976
+ await ref.set(params.data, { merge: true });
9977
+ return { ok: true };
9978
+ });
9979
+ register("graph.recordScore", async (_uid, params) => {
9980
+ const db = admin17.firestore();
9981
+ const histRef = db.collection("context_graph").doc(params.productId).collection("score_history").doc(params.snapshotId);
9982
+ await histRef.set(params.snapshot);
9983
+ if (params.jobUpdate) {
9984
+ const jobRef = db.collection("premortem_jobs").doc(params.productId);
9985
+ const jobDoc = await jobRef.get();
9986
+ if (jobDoc.exists) {
9987
+ await jobRef.update(params.jobUpdate);
9988
+ }
9989
+ }
9990
+ return { ok: true };
9991
+ });
9992
+ register("graph.deleteAll", async (_uid, params) => {
9993
+ const db = admin17.firestore();
9994
+ const subs = ["entities", "edges", "bindings", "test_cases", "nodes"];
9995
+ for (const sub of subs) {
9996
+ const snap = await db.collection("context_graph").doc(params.productId).collection(sub).get();
9997
+ if (!snap.empty) {
9998
+ const batch = db.batch();
9999
+ snap.docs.forEach((d) => batch.delete(d.ref));
10000
+ await batch.commit();
10001
+ }
10002
+ }
10003
+ return { ok: true };
10004
+ });
10005
+ register("graph.hasConstraints", async (_uid, params) => {
10006
+ const snap = await graphCol(params.productId, "nodes").limit(1).get();
10007
+ return { hasConstraints: !snap.empty };
10008
+ });
10009
+ register("graph.updateEmbedding", async (_uid, params) => {
10010
+ const ref = graphCol(params.productId, params.collection || "entities").doc(params.docId);
10011
+ await ref.update({ embedding: params.embedding });
10012
+ return { ok: true };
10013
+ });
10014
+ register("template.list", async (uid, params) => {
10015
+ const db = admin17.firestore();
10016
+ let query = db.collection("templates").where("uid", "==", uid);
10017
+ if (params.type) {
10018
+ query = query.where("type", "==", params.type);
10019
+ }
10020
+ const snap = await query.get();
10021
+ return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
10022
+ });
10023
+ register("template.get", async (uid, params) => {
10024
+ const db = admin17.firestore();
10025
+ const doc = await db.collection("templates").doc(params.id).get();
10026
+ if (!doc.exists)
10027
+ return { doc: null };
10028
+ const data = doc.data();
10029
+ if (data?.uid !== uid)
10030
+ return { doc: null };
10031
+ return { doc: { id: doc.id, ...data } };
10032
+ });
10033
+ register("template.create", async (uid, params) => {
10034
+ const db = admin17.firestore();
10035
+ const id = params.id || db.collection("templates").doc().id;
10036
+ const ref = db.collection("templates").doc(id);
10037
+ await ref.set({ ...params.data, uid, createdAt: admin17.firestore.FieldValue.serverTimestamp() });
10038
+ return { id: ref.id };
10039
+ });
10040
+ register("template.update", async (uid, params) => {
10041
+ const db = admin17.firestore();
10042
+ const ref = db.collection("templates").doc(params.id);
10043
+ const doc = await ref.get();
10044
+ if (!doc.exists || doc.data()?.uid !== uid) {
10045
+ throw new Error("Not found or not authorized");
10046
+ }
10047
+ await ref.update(params.data);
10048
+ return { ok: true };
10049
+ });
10050
+ register("scan.save", async (uid, params) => {
10051
+ const db = admin17.firestore();
10052
+ const collection = params.collection || "scan_reports";
10053
+ const id = params.id || db.collection(collection).doc().id;
10054
+ const ref = db.collection(collection).doc(id);
10055
+ await ref.set({ ...params.data, uid, createdAt: admin17.firestore.FieldValue.serverTimestamp() });
10056
+ return { id: ref.id };
10057
+ });
10058
+ register("scan.rateCheck", async (uid, _params) => {
10059
+ const db = admin17.firestore();
10060
+ const ref = db.collection("users").doc(uid);
10061
+ const doc = await ref.get();
10062
+ if (!doc.exists) {
10063
+ return { scanCount: 0, periodStart: null };
10064
+ }
10065
+ const data = doc.data();
10066
+ return {
10067
+ scanCount: data?.freeScanCount ?? 0,
10068
+ periodStart: data?.freeScanPeriodStart?.toDate?.()?.toISOString() ?? null,
10069
+ subscription: data?.subscription?.status ?? "free"
10070
+ };
10071
+ });
10072
+ register("scan.rateUpdate", async (uid, params) => {
10073
+ const db = admin17.firestore();
10074
+ const ref = db.collection("users").doc(uid);
10075
+ await ref.set(params.data, { merge: true });
10076
+ return { ok: true };
10077
+ });
10078
+ register("readiness.get", async (_uid, params) => {
10079
+ const db = admin17.firestore();
10080
+ const doc = await db.collection("readiness_reports").doc(params.id).get();
10081
+ return { doc: doc.exists ? { id: doc.id, ...doc.data() } : null };
10082
+ });
10083
+ register("readiness.save", async (_uid, params) => {
10084
+ const db = admin17.firestore();
10085
+ const ref = db.collection("readiness_reports").doc(params.id);
10086
+ await ref.set(params.data);
10087
+ return { ok: true };
10088
+ });
10089
+ register("persona.list", async (uid, params) => {
10090
+ const db = admin17.firestore();
10091
+ let query = db.collection("users").doc(uid).collection("personas");
10092
+ if (params.productId) {
10093
+ query = query.where("productId", "==", params.productId);
10094
+ }
10095
+ const snap = await query.orderBy("createdAt", "desc").get();
10096
+ return { docs: snap.docs.map((d) => ({ id: d.id, ...d.data() })) };
10097
+ });
10098
+ register("persona.get", async (uid, params) => {
10099
+ const db = admin17.firestore();
10100
+ const doc = await db.collection("users").doc(uid).collection("personas").doc(params.id).get();
10101
+ if (!doc.exists)
10102
+ return { doc: null };
10103
+ return { doc: { id: doc.id, ...doc.data() } };
10104
+ });
10105
+ var mcpDataProxy = onRequest20({
10106
+ timeoutSeconds: 60,
10107
+ memory: "256MiB",
10108
+ cors: true
10109
+ }, async (req, res) => {
10110
+ ensureFirebaseAdmin();
10111
+ if (req.method === "OPTIONS") {
10112
+ res.status(204).send("");
10113
+ return;
10114
+ }
10115
+ if (req.method !== "POST") {
10116
+ res.status(405).json({ error: "Method not allowed" });
10117
+ return;
10118
+ }
10119
+ const authHeader = req.headers.authorization;
10120
+ if (!authHeader?.startsWith("Bearer ")) {
10121
+ res.status(401).json({ error: "Missing or invalid Authorization header" });
10122
+ return;
10123
+ }
10124
+ let decoded;
10125
+ try {
10126
+ decoded = await admin17.auth().verifyIdToken(authHeader.slice(7));
10127
+ } catch (error6) {
10128
+ if (error6.code === "auth/id-token-expired") {
10129
+ res.status(401).json({ error: "Token expired" });
10130
+ return;
10131
+ }
10132
+ res.status(401).json({ error: "Invalid token" });
10133
+ return;
10134
+ }
10135
+ const uid = decoded.uid;
10136
+ const { action, params } = req.body || {};
10137
+ if (!action || typeof action !== "string") {
10138
+ res.status(400).json({ error: "Missing action" });
10139
+ return;
10140
+ }
10141
+ const handler = handlers[action];
10142
+ if (!handler) {
10143
+ res.status(400).json({ error: `Unknown action: ${action}` });
10144
+ return;
10145
+ }
10146
+ try {
10147
+ const result = await handler(uid, params || {});
10148
+ res.json(result);
10149
+ } catch (error6) {
10150
+ logger4.error(`mcpDataProxy action=${action} error`, { uid, error: error6.message });
10151
+ res.status(error6.message?.includes("not authorized") ? 403 : 500).json({ error: error6.message || "Internal error" });
10152
+ }
10153
+ });
10154
+
9733
10155
  // ../lib/subscription/cancel-scheduled.js
9734
10156
  import { onSchedule } from "firebase-functions/v2/scheduler";
9735
10157
  import Stripe2 from "stripe";
9736
- import admin17 from "firebase-admin";
9737
- import { logger as logger4 } from "firebase-functions";
10158
+ import admin18 from "firebase-admin";
10159
+ import { logger as logger5 } from "firebase-functions";
9738
10160
  ensureFirebaseAdmin();
9739
10161
  function getStripeInstance() {
9740
10162
  const secretKey = process.env.STRIPE_SECRET_KEY;
@@ -9746,7 +10168,7 @@ function getStripeInstance() {
9746
10168
  });
9747
10169
  }
9748
10170
  function getUsersCollection() {
9749
- return admin17.firestore().collection("users");
10171
+ return admin18.firestore().collection("users");
9750
10172
  }
9751
10173
  var cancelScheduledSubscriptions = onSchedule({
9752
10174
  schedule: "every day 00:00",
@@ -9756,20 +10178,20 @@ var cancelScheduledSubscriptions = onSchedule({
9756
10178
  timeoutSeconds: 540
9757
10179
  }, async (event) => {
9758
10180
  try {
9759
- logger4.info("[cancel-scheduled-subscriptions] Starting scheduled cancellation check");
10181
+ logger5.info("[cancel-scheduled-subscriptions] Starting scheduled cancellation check");
9760
10182
  const stripe = getStripeInstance();
9761
10183
  const users = getUsersCollection();
9762
10184
  const now = /* @__PURE__ */ new Date();
9763
10185
  const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
9764
10186
  const todayISO = today.toISOString();
9765
- logger4.info(`[cancel-scheduled-subscriptions] Checking for cancellations on or before ${todayISO}`);
10187
+ logger5.info(`[cancel-scheduled-subscriptions] Checking for cancellations on or before ${todayISO}`);
9766
10188
  const allUsersWithCancellation = await users.where("subscriptionCancellationDate", "<=", todayISO).get();
9767
- logger4.info(`[cancel-scheduled-subscriptions] Found ${allUsersWithCancellation.docs.length} users with cancellation dates <= ${todayISO}`);
10189
+ logger5.info(`[cancel-scheduled-subscriptions] Found ${allUsersWithCancellation.docs.length} users with cancellation dates <= ${todayISO}`);
9768
10190
  const usersToCancel = allUsersWithCancellation.docs.filter((doc) => {
9769
10191
  const data = doc.data();
9770
10192
  return data?.subscription?.id;
9771
10193
  });
9772
- logger4.info(`[cancel-scheduled-subscriptions] Found ${usersToCancel.length} subscriptions to cancel`);
10194
+ logger5.info(`[cancel-scheduled-subscriptions] Found ${usersToCancel.length} subscriptions to cancel`);
9773
10195
  let successCount = 0;
9774
10196
  let errorCount = 0;
9775
10197
  for (const userDoc of usersToCancel) {
@@ -9778,45 +10200,45 @@ var cancelScheduledSubscriptions = onSchedule({
9778
10200
  const subscriptionId = subscription?.id;
9779
10201
  const cancellationDate = userData?.subscriptionCancellationDate;
9780
10202
  if (!subscriptionId) {
9781
- logger4.warn(`[cancel-scheduled-subscriptions] User ${userDoc.id} has cancellation date but no subscription ID`);
10203
+ logger5.warn(`[cancel-scheduled-subscriptions] User ${userDoc.id} has cancellation date but no subscription ID`);
9782
10204
  continue;
9783
10205
  }
9784
10206
  try {
9785
10207
  await stripe.subscriptions.cancel(subscriptionId);
9786
- logger4.info(`[cancel-scheduled-subscriptions] Cancelled Stripe subscription ${subscriptionId} for user ${userDoc.id}`);
10208
+ logger5.info(`[cancel-scheduled-subscriptions] Cancelled Stripe subscription ${subscriptionId} for user ${userDoc.id}`);
9787
10209
  await users.doc(userDoc.id).set({
9788
- subscription: admin17.firestore.FieldValue.delete(),
9789
- subscriptionCancellationDate: admin17.firestore.FieldValue.delete(),
9790
- subscriptionUpdatedAt: admin17.firestore.FieldValue.serverTimestamp()
10210
+ subscription: admin18.firestore.FieldValue.delete(),
10211
+ subscriptionCancellationDate: admin18.firestore.FieldValue.delete(),
10212
+ subscriptionUpdatedAt: admin18.firestore.FieldValue.serverTimestamp()
9791
10213
  }, { merge: true });
9792
- logger4.info(`[cancel-scheduled-subscriptions] Removed subscription from Firestore for user ${userDoc.id}`);
10214
+ logger5.info(`[cancel-scheduled-subscriptions] Removed subscription from Firestore for user ${userDoc.id}`);
9793
10215
  successCount++;
9794
- } catch (error5) {
9795
- logger4.error({
10216
+ } catch (error6) {
10217
+ logger5.error({
9796
10218
  userId: userDoc.id,
9797
10219
  subscriptionId,
9798
10220
  cancellationDate,
9799
- error: error5?.message
10221
+ error: error6?.message
9800
10222
  }, `[cancel-scheduled-subscriptions] Failed to cancel subscription for user ${userDoc.id}`);
9801
10223
  errorCount++;
9802
10224
  }
9803
10225
  }
9804
- logger4.info({
10226
+ logger5.info({
9805
10227
  total: usersToCancel.length,
9806
10228
  success: successCount,
9807
10229
  errors: errorCount
9808
10230
  }, "[cancel-scheduled-subscriptions] Completed scheduled cancellation check");
9809
- } catch (error5) {
9810
- logger4.error({ error: error5?.message, stack: error5?.stack }, "[cancel-scheduled-subscriptions] Fatal error in scheduled function");
9811
- throw error5;
10231
+ } catch (error6) {
10232
+ logger5.error({ error: error6?.message, stack: error6?.stack }, "[cancel-scheduled-subscriptions] Fatal error in scheduled function");
10233
+ throw error6;
9812
10234
  }
9813
10235
  });
9814
10236
 
9815
10237
  // ../lib/personas/cancel-scheduled.js
9816
10238
  import { onSchedule as onSchedule2 } from "firebase-functions/v2/scheduler";
9817
10239
  import Stripe3 from "stripe";
9818
- import admin18 from "firebase-admin";
9819
- import { logger as logger5 } from "firebase-functions";
10240
+ import admin19 from "firebase-admin";
10241
+ import { logger as logger6 } from "firebase-functions";
9820
10242
  ensureFirebaseAdmin();
9821
10243
  function getStripeInstance2() {
9822
10244
  const secretKey = process.env.STRIPE_SECRET_KEY;
@@ -9828,7 +10250,7 @@ function getStripeInstance2() {
9828
10250
  });
9829
10251
  }
9830
10252
  function getUsersCollection2() {
9831
- return admin18.firestore().collection("users");
10253
+ return admin19.firestore().collection("users");
9832
10254
  }
9833
10255
  var cancelScheduledPersonas = onSchedule2({
9834
10256
  schedule: "every day 00:00",
@@ -9838,7 +10260,7 @@ var cancelScheduledPersonas = onSchedule2({
9838
10260
  timeoutSeconds: 540
9839
10261
  }, async (event) => {
9840
10262
  try {
9841
- logger5.info("[cancel-scheduled-personas] Starting scheduled persona cancellation check");
10263
+ logger6.info("[cancel-scheduled-personas] Starting scheduled persona cancellation check");
9842
10264
  const stripe = getStripeInstance2();
9843
10265
  const users = getUsersCollection2();
9844
10266
  const now = /* @__PURE__ */ new Date();
@@ -9856,7 +10278,7 @@ var cancelScheduledPersonas = onSchedule2({
9856
10278
  const cancellationDate = data?.lifecycle?.cancellation_date;
9857
10279
  if (!cancellationDate)
9858
10280
  return false;
9859
- const cancelDate = cancellationDate instanceof admin18.firestore.Timestamp ? cancellationDate.toDate() : new Date(cancellationDate);
10281
+ const cancelDate = cancellationDate instanceof admin19.firestore.Timestamp ? cancellationDate.toDate() : new Date(cancellationDate);
9860
10282
  return cancelDate <= today;
9861
10283
  });
9862
10284
  totalPersonasToCancel += personasWithCancellation.length;
@@ -9876,43 +10298,43 @@ var cancelScheduledPersonas = onSchedule2({
9876
10298
  const subscription = subscriptions.data.find((sub) => sub.items.data.some((item) => item.id === subscriptionItemId));
9877
10299
  if (subscription && !subscription.cancel_at_period_end) {
9878
10300
  await stripe.subscriptions.cancel(subscription.id);
9879
- logger5.info(`[cancel-scheduled-personas] Cancelled Stripe subscription ${subscription.id} for persona ${personaId} (user ${userId})`);
10301
+ logger6.info(`[cancel-scheduled-personas] Cancelled Stripe subscription ${subscription.id} for persona ${personaId} (user ${userId})`);
9880
10302
  }
9881
10303
  }
9882
10304
  }
9883
10305
  await personasRef.doc(personaId).set({
9884
10306
  "lifecycle.status": "archived",
9885
- "lifecycle.cancellation_date": admin18.firestore.FieldValue.delete(),
9886
- updatedAt: admin18.firestore.FieldValue.serverTimestamp()
10307
+ "lifecycle.cancellation_date": admin19.firestore.FieldValue.delete(),
10308
+ updatedAt: admin19.firestore.FieldValue.serverTimestamp()
9887
10309
  }, { merge: true });
9888
- logger5.info(`[cancel-scheduled-personas] Archived persona ${personaId} for user ${userId}`);
10310
+ logger6.info(`[cancel-scheduled-personas] Archived persona ${personaId} for user ${userId}`);
9889
10311
  successCount++;
9890
- } catch (error5) {
9891
- logger5.error({
10312
+ } catch (error6) {
10313
+ logger6.error({
9892
10314
  userId,
9893
10315
  personaId,
9894
10316
  subscriptionItemId,
9895
- error: error5?.message
10317
+ error: error6?.message
9896
10318
  }, `[cancel-scheduled-personas] Failed to cancel persona ${personaId} for user ${userId}`);
9897
10319
  errorCount++;
9898
10320
  }
9899
10321
  }
9900
10322
  }
9901
- logger5.info({
10323
+ logger6.info({
9902
10324
  total: totalPersonasToCancel,
9903
10325
  success: successCount,
9904
10326
  errors: errorCount
9905
10327
  }, "[cancel-scheduled-personas] Completed scheduled persona cancellation check");
9906
- } catch (error5) {
9907
- logger5.error({ error: error5?.message, stack: error5?.stack }, "[cancel-scheduled-personas] Fatal error in scheduled function");
9908
- throw error5;
10328
+ } catch (error6) {
10329
+ logger6.error({ error: error6?.message, stack: error6?.stack }, "[cancel-scheduled-personas] Fatal error in scheduled function");
10330
+ throw error6;
9909
10331
  }
9910
10332
  });
9911
10333
 
9912
10334
  // ../lib/trial/expire-trials.js
9913
10335
  import { onSchedule as onSchedule3 } from "firebase-functions/v2/scheduler";
9914
- import admin19 from "firebase-admin";
9915
- import { logger as logger6 } from "firebase-functions";
10336
+ import admin20 from "firebase-admin";
10337
+ import { logger as logger7 } from "firebase-functions";
9916
10338
  ensureFirebaseAdmin();
9917
10339
  function getTrialConfig() {
9918
10340
  const isProduction = process.env.GCLOUD_PROJECT === "cutline-prod" || process.env.K_SERVICE?.includes("prod");
@@ -9955,18 +10377,18 @@ var expireTrials = onSchedule3({
9955
10377
  // Reduced since it runs frequently now
9956
10378
  }, async (event) => {
9957
10379
  const config = getTrialConfig();
9958
- logger6.info({
10380
+ logger7.info({
9959
10381
  trialDuration: config.durationLabel,
9960
10382
  schedule: scheduleConfig.scheduleLabel,
9961
10383
  checkTime: (/* @__PURE__ */ new Date()).toISOString()
9962
10384
  }, "[expire-trials] Starting trial expiration check");
9963
10385
  try {
9964
- const db = admin19.firestore();
10386
+ const db = admin20.firestore();
9965
10387
  const users = db.collection("users");
9966
10388
  const now = Date.now();
9967
10389
  const expirationThreshold = now - config.durationMs;
9968
10390
  const expiredTrials = await users.where("trialStatus", "==", "active").where("trialStartedAt", "<=", new Date(expirationThreshold)).get();
9969
- logger6.info({
10391
+ logger7.info({
9970
10392
  foundCount: expiredTrials.docs.length,
9971
10393
  expirationThreshold: new Date(expirationThreshold).toISOString()
9972
10394
  }, "[expire-trials] Found trials to expire");
@@ -9976,36 +10398,36 @@ var expireTrials = onSchedule3({
9976
10398
  try {
9977
10399
  await users.doc(userDoc.id).update({
9978
10400
  trialStatus: "expired",
9979
- trialExpiredAt: admin19.firestore.FieldValue.serverTimestamp()
10401
+ trialExpiredAt: admin20.firestore.FieldValue.serverTimestamp()
9980
10402
  });
9981
- logger6.info({ userId: userDoc.id }, "[expire-trials] Expired trial for user");
10403
+ logger7.info({ userId: userDoc.id }, "[expire-trials] Expired trial for user");
9982
10404
  successCount++;
9983
- } catch (error5) {
9984
- logger6.error({
10405
+ } catch (error6) {
10406
+ logger7.error({
9985
10407
  userId: userDoc.id,
9986
- error: error5?.message
10408
+ error: error6?.message
9987
10409
  }, "[expire-trials] Failed to expire trial");
9988
10410
  errorCount++;
9989
10411
  }
9990
10412
  }
9991
- logger6.info({
10413
+ logger7.info({
9992
10414
  total: expiredTrials.docs.length,
9993
10415
  success: successCount,
9994
10416
  errors: errorCount,
9995
10417
  trialDuration: config.durationLabel
9996
10418
  }, "[expire-trials] Completed trial expiration check");
9997
- } catch (error5) {
9998
- logger6.error({
9999
- error: error5?.message,
10000
- stack: error5?.stack
10419
+ } catch (error6) {
10420
+ logger7.error({
10421
+ error: error6?.message,
10422
+ stack: error6?.stack
10001
10423
  }, "[expire-trials] Fatal error in scheduled function");
10002
- throw error5;
10424
+ throw error6;
10003
10425
  }
10004
10426
  });
10005
10427
 
10006
10428
  // ../lib/persona-testing/trigger.js
10007
10429
  import { onDocumentCreated as onDocumentCreated2 } from "firebase-functions/v2/firestore";
10008
- import * as logger7 from "firebase-functions/logger";
10430
+ import * as logger8 from "firebase-functions/logger";
10009
10431
  import { getFirestore as getFirestore2, FieldValue } from "firebase-admin/firestore";
10010
10432
  function getPersonaTesterUrl() {
10011
10433
  const url = process.env.PERSONA_TESTER_URL;
@@ -10017,24 +10439,24 @@ function getPersonaTesterUrl() {
10017
10439
  var onPersonaTestCreated = onDocumentCreated2("users/{userId}/personas/{personaId}/tests/{testId}", async (event) => {
10018
10440
  const snap = event.data;
10019
10441
  if (!snap) {
10020
- logger7.error("[PersonaTest] No data in event");
10442
+ logger8.error("[PersonaTest] No data in event");
10021
10443
  return;
10022
10444
  }
10023
10445
  const { userId, personaId, testId } = event.params;
10024
10446
  const testData = snap.data();
10025
- logger7.info(`[PersonaTest] New test created: ${testId}`, {
10447
+ logger8.info(`[PersonaTest] New test created: ${testId}`, {
10026
10448
  userId,
10027
10449
  personaId,
10028
10450
  testId,
10029
10451
  status: testData.status
10030
10452
  });
10031
10453
  if (testData.status !== "queued") {
10032
- logger7.info(`[PersonaTest] Skipping test ${testId} - status is ${testData.status}`);
10454
+ logger8.info(`[PersonaTest] Skipping test ${testId} - status is ${testData.status}`);
10033
10455
  return;
10034
10456
  }
10035
10457
  try {
10036
10458
  const personaTesterUrl = getPersonaTesterUrl();
10037
- logger7.info(`[PersonaTest] Calling Cloud Run service for test ${testId}`, { url: personaTesterUrl });
10459
+ logger8.info(`[PersonaTest] Calling Cloud Run service for test ${testId}`, { url: personaTesterUrl });
10038
10460
  const response = await fetch(`${personaTesterUrl}/execute`, {
10039
10461
  method: "POST",
10040
10462
  headers: {
@@ -10051,10 +10473,10 @@ var onPersonaTestCreated = onDocumentCreated2("users/{userId}/personas/{personaI
10051
10473
  throw new Error(`Cloud Run service returned ${response.status}: ${errorText}`);
10052
10474
  }
10053
10475
  const result = await response.json();
10054
- logger7.info(`[PersonaTest] Test ${testId} execution started`, result);
10055
- } catch (error5) {
10056
- const err = error5;
10057
- logger7.error(`[PersonaTest] Failed to trigger test ${testId}:`, err);
10476
+ logger8.info(`[PersonaTest] Test ${testId} execution started`, result);
10477
+ } catch (error6) {
10478
+ const err = error6;
10479
+ logger8.error(`[PersonaTest] Failed to trigger test ${testId}:`, err);
10058
10480
  const firestore = getFirestore2();
10059
10481
  await firestore.collection("users").doc(userId).collection("personas").doc(personaId).collection("tests").doc(testId).update({
10060
10482
  status: "failed",