paisa-mcp 0.2.0 → 0.3.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.
package/dist/index.js CHANGED
@@ -53300,7 +53300,7 @@ async function initCrypto(client, pin, userId) {
53300
53300
  // ../../node_modules/.bun/@modelcontextprotocol+server@2.1.0/node_modules/@modelcontextprotocol/server/dist/index.mjs
53301
53301
  var DEFAULT_MAX_REQUEST_BODY_SIZE = 4 * 1024 * 1024;
53302
53302
 
53303
- // ../../node_modules/.bun/@nimit9+signet-server@0.2.2+e803b2305afdb064/node_modules/@nimit9/signet-server/dist/http/status-codes.js
53303
+ // ../../node_modules/.bun/@nimit9+signet-server@0.2.3+e803b2305afdb064/node_modules/@nimit9/signet-server/dist/http/status-codes.js
53304
53304
  var STATUS_CODES = {
53305
53305
  400: "BAD_REQUEST",
53306
53306
  401: "UNAUTHORIZED",
@@ -53314,7 +53314,7 @@ var STATUS_CODES = {
53314
53314
  429: "RATE_LIMITED"
53315
53315
  };
53316
53316
 
53317
- // ../../node_modules/.bun/@nimit9+signet-server@0.2.2+e803b2305afdb064/node_modules/@nimit9/signet-server/dist/mcp/server.js
53317
+ // ../../node_modules/.bun/@nimit9+signet-server@0.2.3+e803b2305afdb064/node_modules/@nimit9/signet-server/dist/mcp/server.js
53318
53318
  var RAW = Symbol.for("signet.mcp.rawResult");
53319
53319
  function toolResult(result) {
53320
53320
  return Object.defineProperty({ ...result }, RAW, { value: true, enumerable: false });
@@ -53398,10 +53398,17 @@ function toResult(value, structured) {
53398
53398
  return { content: [{ type: "text", text }] };
53399
53399
  }
53400
53400
  function createMcpServer(options) {
53401
+ const unlisted = new Set(options.tools.filter((t) => t.listed === false).map((t) => t.name));
53402
+ const toolsCapability = { tools: { listChanged: false } };
53401
53403
  const server = new McpServer({ name: options.name, version: options.version }, {
53402
- capabilities: { tools: { listChanged: false } },
53404
+ ...unlisted.size ? {} : { capabilities: toolsCapability },
53403
53405
  ...options.instructions ? { instructions: options.instructions } : {}
53404
53406
  });
53407
+ let restore;
53408
+ if (unlisted.size) {
53409
+ server.server.registerCapabilities(toolsCapability);
53410
+ restore = hideUnlisted(server, unlisted);
53411
+ }
53405
53412
  const register2 = server.registerTool.bind(server);
53406
53413
  const { c, token } = options.context ?? {};
53407
53414
  for (const tool of options.tools) {
@@ -53445,29 +53452,110 @@ function createMcpServer(options) {
53445
53452
  ...tool.input ? { inputSchema: tool.input } : {},
53446
53453
  ...tool.output ? { outputSchema: tool.output } : {}
53447
53454
  }, tool.input ? (input2, mcp) => run(input2, mcp) : (mcp) => run({}, mcp));
53455
+ restore?.();
53456
+ restore = undefined;
53448
53457
  }
53449
53458
  return server;
53450
53459
  }
53460
+ function hideUnlisted(server, unlisted) {
53461
+ const inner = server.server;
53462
+ const original = inner.setRequestHandler.bind(inner);
53463
+ let caught = false;
53464
+ inner.setRequestHandler = (method, handler) => {
53465
+ if (method !== "tools/list" || typeof handler !== "function")
53466
+ return original(method, handler);
53467
+ caught = true;
53468
+ original(method, async (request, ctx) => {
53469
+ const result = await handler(request, ctx);
53470
+ return { ...result, tools: result.tools.filter((t) => !unlisted.has(t.name)) };
53471
+ });
53472
+ };
53473
+ return () => {
53474
+ delete inner.setRequestHandler;
53475
+ if (!caught)
53476
+ throw new Error("signet mcp: could not hide unlisted tools; @modelcontextprotocol/server no longer installs tools/list through setRequestHandler");
53477
+ };
53478
+ }
53479
+
53480
+ // src/annotations.ts
53481
+ var RO = { readOnlyHint: true, openWorldHint: false };
53482
+ var WI = {
53483
+ readOnlyHint: false,
53484
+ destructiveHint: false,
53485
+ idempotentHint: true,
53486
+ openWorldHint: false
53487
+ };
53488
+ var W = {
53489
+ readOnlyHint: false,
53490
+ destructiveHint: false,
53491
+ idempotentHint: false,
53492
+ openWorldHint: false
53493
+ };
53494
+ var D = {
53495
+ readOnlyHint: false,
53496
+ destructiveHint: true,
53497
+ idempotentHint: false,
53498
+ openWorldHint: false
53499
+ };
53500
+ var WI_OPEN = {
53501
+ readOnlyHint: false,
53502
+ destructiveHint: false,
53503
+ idempotentHint: true,
53504
+ openWorldHint: true
53505
+ };
53506
+ var TOOL_META = {
53507
+ get_transactions: { title: "Search Transactions", annotations: RO },
53508
+ get_uncategorized_groups: { title: "Group Uncategorized Transactions", annotations: RO },
53509
+ categorize_groups: { title: "Categorize Transaction Groups", annotations: W },
53510
+ backfill_persons: { title: "Backfill Persons from Transactions", annotations: WI },
53511
+ update_transaction: { title: "Update Transaction", annotations: WI },
53512
+ bulk_link_entity: { title: "Bulk Link Transactions", annotations: WI },
53513
+ manage_duplicates: { title: "Manage Duplicate Transactions", annotations: W },
53514
+ get_reconciliation_context: { title: "Get Reconciliation Context", annotations: RO },
53515
+ bulk_categorize_transactions: { title: "Bulk Categorize Transactions", annotations: WI },
53516
+ delete_transactions: { title: "Delete Transactions", annotations: D },
53517
+ rescan_transactions: { title: "Rescan Transactions", annotations: WI },
53518
+ get_settlement_candidates: { title: "Find Settlement Candidates", annotations: RO },
53519
+ get_transaction: { title: "Get Transaction", annotations: RO },
53520
+ preview_import: { title: "Preview Statement Import", annotations: RO },
53521
+ import_statement: { title: "Import Statement", annotations: W },
53522
+ auto_categorize_jev: { title: "Auto-Categorize with Jev", annotations: W },
53523
+ list_entities: { title: "List Entities", annotations: RO },
53524
+ upsert_entity: { title: "Create or Update Entity", annotations: W },
53525
+ delete_entity: { title: "Delete Entity", annotations: D },
53526
+ merge_merchants: { title: "Merge Merchants", annotations: D },
53527
+ get_analytics: { title: "Get Analytics", annotations: RO },
53528
+ upsert_savings: { title: "Create or Update Savings Vehicle", annotations: W },
53529
+ contribute_to_goal: { title: "Contribute to Goal", annotations: W },
53530
+ set_budget: { title: "Set Budget", annotations: WI },
53531
+ get_dashboard: { title: "Get Dashboard", annotations: RO },
53532
+ sync_recurring: { title: "Sync Recurring Merchants", annotations: WI },
53533
+ check_alerts: { title: "Check Alerts", annotations: W },
53534
+ manage_alerts: { title: "Manage Alerts and Rules", annotations: WI },
53535
+ manage_debt: { title: "Add or Settle Debt", annotations: W },
53536
+ generate_monthly_report: { title: "Generate Monthly Report", annotations: WI },
53537
+ get_report: { title: "Get Report", annotations: RO },
53538
+ export_transactions: { title: "Export Transactions", annotations: RO },
53539
+ set_learning_rule: { title: "Set Learning Rule", annotations: WI },
53540
+ update_net_worth: { title: "Update Net Worth", annotations: WI },
53541
+ upsert_investment: { title: "Create or Update Investment", annotations: W },
53542
+ sync_zerodha: { title: "Sync Zerodha", annotations: WI_OPEN },
53543
+ get_settings: { title: "Get Settings", annotations: RO },
53544
+ update_settings: { title: "Update Settings", annotations: WI },
53545
+ set_encryption_mode: { title: "Set Encryption Mode", annotations: D }
53546
+ };
53547
+ function applyAnnotations(tools) {
53548
+ return tools.map((tool) => {
53549
+ const meta3 = TOOL_META[tool.name];
53550
+ if (!meta3)
53551
+ throw new Error(`No TOOL_META entry for tool "${tool.name}" — add one to annotations.ts`);
53552
+ return { ...tool, title: meta3.title, annotations: meta3.annotations };
53553
+ });
53554
+ }
53451
53555
  // src/lib/union-tool.ts
53452
53556
  function variant(input2, run) {
53453
53557
  return { input: input2, run };
53454
53558
  }
53455
- function isAlias(tool) {
53456
- return typeof tool.aliasFor === "string";
53457
- }
53458
- function aliasTool(name, input2, aliasFor, note, route) {
53459
- const tool = defineTool({
53460
- name,
53461
- description: `Deprecated alias of ${aliasFor}.`,
53462
- input: input2,
53463
- handler: async (args, ctx) => {
53464
- const [to, next] = route(args);
53465
- const parsed = to.input ? await to.input.parseAsync(next) : next;
53466
- return to.handler(parsed, ctx);
53467
- }
53468
- });
53469
- return { ...tool, aliasFor, aliasNote: note };
53470
- }
53471
53559
  function compactJsonSchema(schema) {
53472
53560
  const walk = (node2, root) => {
53473
53561
  if (Array.isArray(node2))
@@ -53564,91 +53652,7 @@ function unionTool(opts) {
53564
53652
  return v.run(rest, ctx);
53565
53653
  }
53566
53654
  });
53567
- return {
53568
- tool,
53569
- alias: (aliasName, value) => aliasTool(aliasName, variants[value].input, name, `${key}: "${value}"`, (a) => [
53570
- tool,
53571
- { ...a, [key]: value }
53572
- ])
53573
- };
53574
- }
53575
-
53576
- // src/annotations.ts
53577
- var RO = { readOnlyHint: true, openWorldHint: false };
53578
- var WI = {
53579
- readOnlyHint: false,
53580
- destructiveHint: false,
53581
- idempotentHint: true,
53582
- openWorldHint: false
53583
- };
53584
- var W = {
53585
- readOnlyHint: false,
53586
- destructiveHint: false,
53587
- idempotentHint: false,
53588
- openWorldHint: false
53589
- };
53590
- var D = {
53591
- readOnlyHint: false,
53592
- destructiveHint: true,
53593
- idempotentHint: false,
53594
- openWorldHint: false
53595
- };
53596
- var WI_OPEN = {
53597
- readOnlyHint: false,
53598
- destructiveHint: false,
53599
- idempotentHint: true,
53600
- openWorldHint: true
53601
- };
53602
- var TOOL_META = {
53603
- get_transactions: { title: "Search Transactions", annotations: RO },
53604
- get_uncategorized_groups: { title: "Group Uncategorized Transactions", annotations: RO },
53605
- categorize_groups: { title: "Categorize Transaction Groups", annotations: W },
53606
- backfill_persons: { title: "Backfill Persons from Transactions", annotations: WI },
53607
- update_transaction: { title: "Update Transaction", annotations: WI },
53608
- bulk_link_entity: { title: "Bulk Link Transactions", annotations: WI },
53609
- manage_duplicates: { title: "Manage Duplicate Transactions", annotations: W },
53610
- get_reconciliation_context: { title: "Get Reconciliation Context", annotations: RO },
53611
- bulk_categorize_transactions: { title: "Bulk Categorize Transactions", annotations: WI },
53612
- delete_transactions: { title: "Delete Transactions", annotations: D },
53613
- rescan_transactions: { title: "Rescan Transactions", annotations: WI },
53614
- get_settlement_candidates: { title: "Find Settlement Candidates", annotations: RO },
53615
- get_transaction: { title: "Get Transaction", annotations: RO },
53616
- preview_import: { title: "Preview Statement Import", annotations: RO },
53617
- import_statement: { title: "Import Statement", annotations: W },
53618
- auto_categorize_jev: { title: "Auto-Categorize with Jev", annotations: W },
53619
- list_entities: { title: "List Entities", annotations: RO },
53620
- upsert_entity: { title: "Create or Update Entity", annotations: W },
53621
- delete_entity: { title: "Delete Entity", annotations: D },
53622
- merge_merchants: { title: "Merge Merchants", annotations: D },
53623
- get_analytics: { title: "Get Analytics", annotations: RO },
53624
- upsert_savings: { title: "Create or Update Savings Vehicle", annotations: W },
53625
- contribute_to_goal: { title: "Contribute to Goal", annotations: W },
53626
- set_budget: { title: "Set Budget", annotations: WI },
53627
- get_dashboard: { title: "Get Dashboard", annotations: RO },
53628
- sync_recurring: { title: "Sync Recurring Merchants", annotations: WI },
53629
- check_alerts: { title: "Check Alerts", annotations: W },
53630
- manage_alerts: { title: "Manage Alerts and Rules", annotations: WI },
53631
- manage_debt: { title: "Add or Settle Debt", annotations: W },
53632
- generate_monthly_report: { title: "Generate Monthly Report", annotations: WI },
53633
- get_report: { title: "Get Report", annotations: RO },
53634
- export_transactions: { title: "Export Transactions", annotations: RO },
53635
- set_learning_rule: { title: "Set Learning Rule", annotations: WI },
53636
- update_net_worth: { title: "Update Net Worth", annotations: WI },
53637
- upsert_investment: { title: "Create or Update Investment", annotations: W },
53638
- sync_zerodha: { title: "Sync Zerodha", annotations: WI_OPEN },
53639
- get_settings: { title: "Get Settings", annotations: RO },
53640
- update_settings: { title: "Update Settings", annotations: WI },
53641
- set_encryption_mode: { title: "Set Encryption Mode", annotations: D }
53642
- };
53643
- function applyAnnotations(tools) {
53644
- return tools.map((tool) => {
53645
- if (isAlias(tool))
53646
- return tool;
53647
- const meta3 = TOOL_META[tool.name];
53648
- if (!meta3)
53649
- throw new Error(`No TOOL_META entry for tool "${tool.name}" — add one to annotations.ts`);
53650
- return { ...tool, title: meta3.title, annotations: meta3.annotations };
53651
- });
53655
+ return { tool };
53652
53656
  }
53653
53657
 
53654
53658
  // src/prompts.ts
@@ -53809,11 +53813,7 @@ function alertTools(client) {
53809
53813
  return { success: true, generated, unread };
53810
53814
  }
53811
53815
  }),
53812
- manage.tool,
53813
- manage.alias("dismiss_alert", "dismiss"),
53814
- manage.alias("mark_alert_read", "read"),
53815
- manage.alias("list_alert_rules", "list_rules"),
53816
- manage.alias("set_alert_rule", "set_rule")
53816
+ manage.tool
53817
53817
  ];
53818
53818
  }
53819
53819
 
@@ -54142,7 +54142,7 @@ function debtTools(client) {
54142
54142
  })
54143
54143
  }
54144
54144
  });
54145
- return [manage.tool, manage.alias("add_debt", "add"), manage.alias("settle_debt", "settle")];
54145
+ return [manage.tool];
54146
54146
  }
54147
54147
 
54148
54148
  // src/tools/accounts.ts
@@ -54903,11 +54903,7 @@ function reportTools(client) {
54903
54903
  }),
54904
54904
  handler: (body) => client.post("/api/reports/generate", body)
54905
54905
  }),
54906
- report2.tool,
54907
- report2.alias("get_reports", "monthly"),
54908
- report2.alias("get_net_worth", "net_worth"),
54909
- report2.alias("get_upcoming", "upcoming"),
54910
- report2.alias("get_spending_heatmap", "heatmap")
54906
+ report2.tool
54911
54907
  ];
54912
54908
  }
54913
54909
 
@@ -54986,56 +54982,7 @@ function entityTools(client, crypto3) {
54986
54982
  fixed_deposit: investment.deleteFd
54987
54983
  }
54988
54984
  });
54989
- return [
54990
- list.tool,
54991
- upsert.tool,
54992
- del.tool,
54993
- list.alias("list_categories", "categories"),
54994
- list.alias("list_merchants", "merchants"),
54995
- list.alias("list_bank_accounts", "bank_accounts"),
54996
- list.alias("list_persons", "persons"),
54997
- list.alias("list_budgets", "budgets"),
54998
- list.alias("list_debts", "debts"),
54999
- list.alias("list_invites", "invites"),
55000
- list.alias("list_alerts", "alerts"),
55001
- list.alias("list_recurring", "recurring"),
55002
- list.alias("list_push_subscriptions", "push_subscriptions"),
55003
- list.alias("list_saved_reports", "saved_reports"),
55004
- aliasTool("list_learning", exports_external.object({ type: exports_external.enum(LEARNING_SLICES) }), "list_entities", 'entity: "learning", slice: <type>', ({ type }) => [list.tool, { entity: "learning", slice: type }]),
55005
- aliasTool("list_savings", exports_external.object({
55006
- type: exports_external.enum(["goals", "emis", "sinking_funds", "insurance", "contributions"]),
55007
- id: exports_external.string().optional()
55008
- }), "list_entities", "entity: <type> (contributions → goal_contributions)", ({ type, id }) => {
55009
- if (type !== "contributions")
55010
- return [list.tool, { entity: type }];
55011
- if (!id)
55012
- throw new Error("list_savings type='contributions' requires id (goal UUID)");
55013
- return [list.tool, { entity: "goal_contributions", id }];
55014
- }),
55015
- aliasTool("list_investments", exports_external.object({
55016
- type: exports_external.enum(["holdings", "sips", "fixed_deposits", "transactions"]),
55017
- id: exports_external.string().optional()
55018
- }), "list_entities", "entity: <type> (transactions → investment_transactions)", ({ type, id }) => {
55019
- if (type !== "transactions")
55020
- return [list.tool, { entity: type }];
55021
- if (!id)
55022
- throw new Error("list_investments type='transactions' requires id");
55023
- return [list.tool, { entity: "investment_transactions", id }];
55024
- }),
55025
- upsert.alias("upsert_merchant", "merchant"),
55026
- upsert.alias("upsert_person", "person"),
55027
- upsert.alias("upsert_category", "category"),
55028
- upsert.alias("upsert_bank_account", "bank_account"),
55029
- upsert.alias("upsert_insurance", "insurance"),
55030
- upsert.alias("create_invite", "invite"),
55031
- del.alias("delete_category", "category"),
55032
- del.alias("delete_merchant", "merchant"),
55033
- del.alias("delete_person", "person"),
55034
- del.alias("delete_debt", "debt"),
55035
- del.alias("revoke_invite", "invite"),
55036
- aliasTool("delete_savings", exports_external.object({ type: exports_external.enum(["goal", "emi", "insurance", "sinking_fund"]), id: exports_external.string() }), "delete_entity", "entity: <type>", ({ type, id }) => [del.tool, { entity: type, id }]),
55037
- aliasTool("delete_investment", exports_external.object({ type: exports_external.enum(["sip", "fixed_deposit"]), id: exports_external.string() }), "delete_entity", "entity: <type>", ({ type, id }) => [del.tool, { entity: type, id }])
55038
- ];
54985
+ return [list.tool, upsert.tool, del.tool];
55039
54986
  }
55040
54987
 
55041
54988
  // ../reconciliation/src/aliases.ts
@@ -59509,603 +59456,231 @@ function exportTools(client, crypto3) {
59509
59456
  ];
59510
59457
  }
59511
59458
 
59512
- // ../../node_modules/.bun/@typesafe-ai+sdk@0.6.0/node_modules/@typesafe-ai/sdk/dist/index.mjs
59513
- var requestIdFrom = (headers) => headers.get("x-typesafe-request-id") ?? undefined;
59514
- var APIPromise = class APIPromise2 extends Promise {
59515
- #responsePromise;
59516
- #parseResponse;
59517
- #parsed;
59518
- constructor(responsePromise, parseResponse) {
59519
- super((resolve) => resolve(undefined));
59520
- this.#responsePromise = responsePromise;
59521
- this.#parseResponse = parseResponse;
59522
- }
59523
- asResponse() {
59524
- return this.#responsePromise;
59525
- }
59526
- async withResponse() {
59527
- const [data, response] = await Promise.all([this.#parse(), this.#responsePromise]);
59528
- return {
59529
- data,
59530
- response,
59531
- requestId: requestIdFrom(response.headers)
59532
- };
59533
- }
59534
- map(fn2) {
59535
- return new APIPromise2(this.#responsePromise, () => this.#parse().then(fn2));
59536
- }
59537
- #parse() {
59538
- this.#parsed ??= this.#responsePromise.then(this.#parseResponse);
59539
- return this.#parsed;
59540
- }
59541
- then(onfulfilled, onrejected) {
59542
- return this.#parse().then(onfulfilled, onrejected);
59543
- }
59544
- catch(onrejected) {
59545
- return this.#parse().catch(onrejected);
59546
- }
59547
- finally(onfinally) {
59548
- return this.#parse().finally(onfinally);
59549
- }
59550
- };
59551
- var ENV = {
59552
- apiKey: "TYPESAFE_API_KEY",
59553
- baseURL: "TYPESAFE_BASE_URL",
59554
- defaultModel: "TYPESAFE_DEFAULT_MODEL",
59555
- logLevel: "TYPESAFE_LOG_LEVEL"
59556
- };
59557
- var readEnv = (name) => {
59558
- if (typeof process === "undefined" || !process.env)
59559
- return;
59560
- return process.env[name]?.trim() || undefined;
59561
- };
59562
- var fromCodeOrEnv = (fromCode, envVar) => fromCode ?? readEnv(envVar);
59563
- var range = (from, to2) => Array.from({ length: to2 - from }, (_2, i2) => from + i2);
59564
- var DEFAULT_RETRY_POLICY = {
59565
- maxRetries: 2,
59566
- backoffInitialMs: 500,
59567
- backoffMaxMs: 5000,
59568
- backoffJitter: 0.25,
59569
- httpStatuses: /* @__PURE__ */ new Set([
59570
- 408,
59571
- 429,
59572
- ...range(500, 600)
59573
- ]),
59574
- respectRetryAfter: true,
59575
- maxRetryAfterMs: 60000,
59576
- apiConnectionError: true,
59577
- apiTimeoutError: true
59578
- };
59579
- DEFAULT_RETRY_POLICY.maxRetries;
59580
- var isRetryableStatus = (status, policy = DEFAULT_RETRY_POLICY) => policy.httpStatuses.has(status);
59581
- var parseRetryAfter = (headers, now = Date.now()) => {
59582
- const ms = Number(headers.get("retry-after-ms"));
59583
- if (headers.has("retry-after-ms") && Number.isFinite(ms) && ms >= 0)
59584
- return ms;
59585
- const raw = headers.get("retry-after");
59586
- if (raw === null)
59587
- return;
59588
- const seconds = Number(raw);
59589
- if (Number.isFinite(seconds))
59590
- return seconds >= 0 ? seconds * 1000 : undefined;
59591
- const date5 = Date.parse(raw);
59592
- if (!Number.isNaN(date5))
59593
- return Math.max(0, date5 - now);
59594
- };
59595
- var retryDelayMs = (attempt, headers, policy = DEFAULT_RETRY_POLICY, random = Math.random) => {
59596
- if (policy.respectRetryAfter && headers !== undefined) {
59597
- const retryAfter = parseRetryAfter(headers);
59598
- if (retryAfter !== undefined && retryAfter <= policy.maxRetryAfterMs)
59599
- return retryAfter;
59600
- }
59601
- const exponential = Math.min(policy.backoffInitialMs * 2 ** attempt, policy.backoffMaxMs);
59602
- return Math.round(exponential * (1 - random() * policy.backoffJitter));
59603
- };
59604
- var sleep3 = (ms, signal) => new Promise((resolve, reject) => {
59605
- if (signal?.aborted)
59606
- return reject(signal.reason);
59607
- const onAbort = () => {
59608
- clearTimeout(timer);
59609
- reject(signal?.reason);
59610
- };
59611
- const timer = setTimeout(() => {
59612
- signal?.removeEventListener("abort", onAbort);
59613
- resolve();
59614
- }, ms);
59615
- signal?.addEventListener("abort", onAbort, { once: true });
59616
- });
59617
- var TypeSafeError = class extends Error {
59618
- constructor(message, options) {
59619
- super(message, options);
59620
- this.name = new.target.name;
59621
- }
59622
- };
59623
- var isRecord = (value) => typeof value === "object" && value !== null;
59624
- var extractMessage = (body) => {
59625
- if (typeof body === "string")
59626
- return body || undefined;
59627
- if (!isRecord(body))
59628
- return;
59629
- const { error: error62, message, detail } = body;
59630
- if (typeof error62 === "string")
59631
- return error62;
59632
- if (isRecord(error62) && typeof error62.message === "string")
59633
- return error62.message;
59634
- if (typeof message === "string")
59635
- return message;
59636
- if (typeof detail === "string")
59637
- return detail;
59638
- if (isRecord(detail) && typeof detail.message === "string")
59639
- return detail.message;
59640
- if (Array.isArray(detail))
59641
- return describeValidationErrors(detail);
59642
- };
59643
- var describeValidationErrors = (errors3) => {
59644
- const parts = errors3.flatMap((e2) => {
59645
- if (!isRecord(e2) || typeof e2.msg !== "string")
59646
- return [];
59647
- const loc = Array.isArray(e2.loc) ? e2.loc.filter((x2) => x2 !== "body").join(".") : "";
59648
- return [loc ? `${loc}: ${e2.msg}` : e2.msg];
59649
- });
59650
- return parts.length > 0 ? parts.join("; ") : undefined;
59651
- };
59652
- var MAX_RAW_BODY_IN_MESSAGE = 200;
59653
- var APIError = class APIError2 extends TypeSafeError {
59654
- status;
59655
- headers;
59656
- body;
59657
- requestId;
59658
- constructor(status, body, headers, message) {
59659
- super(message ?? APIError2.describe(status, body));
59660
- this.status = status;
59661
- this.body = body;
59662
- this.headers = headers;
59663
- this.requestId = requestIdFrom(headers);
59664
- }
59665
- static describe(status, body) {
59666
- const detail = extractMessage(body);
59667
- if (detail)
59668
- return `${status} ${detail}`;
59669
- if (body === undefined)
59670
- return `${status} status code (no body)`;
59671
- const raw = typeof body === "string" ? body : JSON.stringify(body);
59672
- return `${status} ${raw.length > MAX_RAW_BODY_IN_MESSAGE ? `${raw.slice(0, MAX_RAW_BODY_IN_MESSAGE)}…` : raw}`;
59673
- }
59674
- static fromResponse(status, body, headers) {
59675
- if (status === 400)
59676
- return new BadRequestError(status, body, headers);
59677
- if (status === 401)
59678
- return new AuthenticationError(status, body, headers);
59679
- if (status === 403)
59680
- return new PermissionDeniedError(status, body, headers);
59681
- if (status === 404)
59682
- return new NotFoundError(status, body, headers);
59683
- if (status === 422)
59684
- return new UnprocessableEntityError(status, body, headers);
59685
- if (status === 429)
59686
- return new RateLimitError(status, body, headers);
59687
- if (status >= 500)
59688
- return new InternalServerError(status, body, headers);
59689
- return new APIError2(status, body, headers);
59690
- }
59691
- };
59692
- var BadRequestError = class extends APIError {
59693
- };
59694
- var AuthenticationError = class extends APIError {
59695
- };
59696
- var PermissionDeniedError = class extends APIError {
59697
- };
59698
- var NotFoundError = class extends APIError {
59699
- };
59700
- var UnprocessableEntityError = class extends APIError {
59701
- };
59702
- var RateLimitError = class extends APIError {
59703
- retryAfterMs = parseRetryAfter(this.headers);
59704
- };
59705
- var InternalServerError = class extends APIError {
59706
- };
59707
- var APIConnectionError = class extends TypeSafeError {
59708
- constructor(message = "Connection error.", options) {
59709
- super(message, options);
59710
- }
59711
- };
59712
- var APITimeoutError = class extends APIConnectionError {
59713
- timeoutMs;
59714
- constructor(timeoutMs, options) {
59715
- super(`Request timed out after ${timeoutMs}ms.`, options);
59716
- this.timeoutMs = timeoutMs;
59717
- }
59718
- };
59719
- var APIUserAbortError = class extends TypeSafeError {
59720
- constructor(message = "Request was aborted.", options) {
59721
- super(message, options);
59722
- }
59723
- };
59724
- var LOG_LEVELS = [
59725
- "debug",
59726
- "info",
59727
- "warn",
59728
- "error",
59729
- "off"
59730
- ];
59731
- var DEFAULT_LOG_LEVEL = "warn";
59732
- var isLogLevel = (value) => LOG_LEVELS.includes(value);
59733
- var parseLogLevel = (value, source) => {
59734
- if (isLogLevel(value))
59735
- return value;
59736
- throw new TypeSafeError(`Invalid log level "${value}" from ${source}. Expected one of: ${LOG_LEVELS.join(", ")}.`);
59737
- };
59738
- var PREFIX = "[typesafe-sdk]";
59739
- var consoleLogger = {
59740
- debug: (message, ...args) => console.debug(`${PREFIX} ${message}`, ...args),
59741
- info: (message, ...args) => console.info(`${PREFIX} ${message}`, ...args),
59742
- warn: (message, ...args) => console.warn(`${PREFIX} ${message}`, ...args),
59743
- error: (message, ...args) => console.error(`${PREFIX} ${message}`, ...args)
59744
- };
59745
- var RANK = {
59746
- debug: 0,
59747
- info: 1,
59748
- warn: 2,
59749
- error: 3,
59750
- off: 4
59751
- };
59752
- var drop = () => {};
59753
- var withLevel = (sink, level) => {
59754
- const enabled = (at2) => RANK[at2] >= RANK[level];
59755
- return {
59756
- debug: enabled("debug") ? (message, ...args) => sink.debug(message, ...args) : drop,
59757
- info: enabled("info") ? (message, ...args) => sink.info(message, ...args) : drop,
59758
- warn: enabled("warn") ? (message, ...args) => sink.warn(message, ...args) : drop,
59759
- error: enabled("error") ? (message, ...args) => sink.error(message, ...args) : drop
59760
- };
59761
- };
59762
- var KEY_HEADERS = /* @__PURE__ */ new Set([
59763
- "authorization",
59764
- "proxy-authorization",
59765
- "x-api-key"
59766
- ]);
59767
- var OPAQUE_HEADERS = /* @__PURE__ */ new Set(["cookie", "set-cookie"]);
59768
- var redactKey = (value) => {
59769
- const [scheme, secret] = value.includes(" ") ? value.split(/\s+/, 2) : [undefined, value];
59770
- const tail = secret && secret.length > 8 ? secret.slice(-4) : "";
59771
- return `${scheme ? `${scheme} ` : ""}***${tail}`;
59772
- };
59773
- var redact = (name, value) => {
59774
- const lower = name.toLowerCase();
59775
- if (KEY_HEADERS.has(lower))
59776
- return redactKey(value);
59777
- if (OPAQUE_HEADERS.has(lower))
59778
- return "***";
59779
- return value;
59780
- };
59781
- var redactHeaders = (headers) => Object.fromEntries(Object.entries(headers).map(([name, value]) => [name, redact(name, value)]));
59782
- var choice = (instructions, criteria) => {
59783
- if (Array.isArray(criteria))
59784
- throw new TypeSafeError("Choice criteria must be a map of labels to descriptions, not a list.");
59785
- return {
59786
- type: "choice",
59787
- instructions,
59788
- criteria
59789
- };
59790
- };
59791
- var validateQuestions = (questions) => {
59792
- if (Object.keys(questions).length === 0)
59793
- throw new TypeSafeError("At least one question is required.");
59794
- for (const [name, question] of Object.entries(questions)) {
59795
- if (question.type !== "score")
59796
- continue;
59797
- if (!Array.isArray(question.criteria))
59798
- throw new TypeSafeError(`Score question "${name}" has criteria that are not a list; score criteria must be a list of descriptions indexed by score from zero.`);
59799
- if (question.criteria.length < 2)
59800
- throw new TypeSafeError(`Score question "${name}" has ${question.criteria.length} criteria; at least two scores are required.`);
59801
- }
59802
- };
59803
- var Models = class {
59804
- #transport;
59805
- constructor(transport) {
59806
- this.#transport = transport;
59807
- }
59808
- list(options = {}) {
59809
- return this.#transport.request("GET", "/v1/models", options).map(unwrapModels);
59810
- }
59811
- };
59812
- var unwrapModels = (wire) => {
59813
- if (Array.isArray(wire?.models))
59814
- return wire.models;
59815
- throw new TypeSafeError("Unexpected response shape from GET /v1/models; expected { models: [...] }.");
59816
- };
59817
- var g2 = globalThis;
59818
- var isBrowser = () => typeof g2.window !== "undefined" && typeof g2.window.document !== "undefined" && typeof g2.navigator !== "undefined";
59819
- var describeRuntime = () => {
59820
- const platform = g2.process?.platform && g2.process?.arch ? ` (${g2.process.platform}; ${g2.process.arch})` : "";
59821
- if (g2.Bun?.version)
59822
- return `bun/${g2.Bun.version}${platform}`;
59823
- if (g2.Deno?.version?.deno)
59824
- return `deno/${g2.Deno.version.deno}${platform}`;
59825
- if (g2.EdgeRuntime !== undefined)
59826
- return "vercel-edge";
59827
- if (g2.navigator?.userAgent === "Cloudflare-Workers")
59828
- return "cloudflare-workers";
59829
- if (g2.process?.versions?.node)
59830
- return `node/${g2.process.versions.node}${platform}`;
59831
- if (isBrowser())
59832
- return "browser";
59833
- return "unknown";
59834
- };
59835
- var VERSION2 = "0.6.0";
59836
- var missingApiKey = () => {
59837
- throw new TypeSafeError(`No API key was provided. Pass \`apiKey\` to the TypeSafeClient constructor or set the ${ENV.apiKey} environment variable.`);
59838
- };
59839
- var missingFetch = () => {
59840
- throw new TypeSafeError("No global `fetch` is available in this runtime. Pass a `fetch` implementation to the TypeSafeClient constructor.");
59841
- };
59842
- var refuseBrowser = () => {
59843
- throw new TypeSafeError("TypeSafeClient is running in a browser, which would expose your API key to anyone using the page. Call the API from a server instead, or pass `dangerouslyAllowBrowser: true` if you understand the risk.");
59844
- };
59845
- var defaultFetch = (input2, init) => globalThis.fetch(input2, init);
59846
- var assertNonNegativeInteger = (name, value) => {
59847
- if (!Number.isInteger(value) || value < 0)
59848
- throw new TypeSafeError(`\`${name}\` must be a non-negative integer, got ${String(value)}.`);
59849
- return value;
59850
- };
59851
- var assertPositiveMs = (name, value) => {
59852
- if (!Number.isFinite(value) || value <= 0)
59853
- throw new TypeSafeError(`\`${name}\` must be a positive number of milliseconds, got ${String(value)}.`);
59854
- return value;
59855
- };
59856
- var assertNonNegativeMs = (name, value) => {
59857
- if (!Number.isFinite(value) || value < 0)
59858
- throw new TypeSafeError(`\`${name}\` must be a non-negative number of milliseconds, got ${String(value)}.`);
59859
- return value;
59860
- };
59861
- var assertFraction = (name, value) => {
59862
- if (!Number.isFinite(value) || value < 0 || value > 1)
59863
- throw new TypeSafeError(`\`${name}\` must be between 0 and 1, got ${String(value)}.`);
59864
- return value;
59865
- };
59866
- var assertStatusSet = (name, statuses) => {
59867
- for (const status of statuses)
59868
- if (!Number.isInteger(status) || status < 100 || status > 999)
59869
- throw new TypeSafeError(`\`${name}\` must contain HTTP status codes, got ${String(status)}.`);
59870
- return statuses;
59871
- };
59872
- var resolveRetryPolicy = (base, overrides) => {
59873
- const o2 = overrides ?? {};
59874
- return {
59875
- maxRetries: o2.maxRetries === undefined ? base.maxRetries : assertNonNegativeInteger("retry.maxRetries", o2.maxRetries),
59876
- backoffInitialMs: o2.backoffInitialMs === undefined ? base.backoffInitialMs : assertNonNegativeMs("retry.backoffInitialMs", o2.backoffInitialMs),
59877
- backoffMaxMs: o2.backoffMaxMs === undefined ? base.backoffMaxMs : assertNonNegativeMs("retry.backoffMaxMs", o2.backoffMaxMs),
59878
- backoffJitter: o2.backoffJitter === undefined ? base.backoffJitter : assertFraction("retry.backoffJitter", o2.backoffJitter),
59879
- httpStatuses: new Set(o2.httpStatuses === undefined ? base.httpStatuses : assertStatusSet("retry.httpStatuses", o2.httpStatuses)),
59880
- respectRetryAfter: o2.respectRetryAfter ?? base.respectRetryAfter,
59881
- maxRetryAfterMs: o2.maxRetryAfterMs === undefined ? base.maxRetryAfterMs : assertNonNegativeMs("retry.maxRetryAfterMs", o2.maxRetryAfterMs),
59882
- apiConnectionError: o2.apiConnectionError ?? base.apiConnectionError,
59883
- apiTimeoutError: o2.apiTimeoutError ?? base.apiTimeoutError
59884
- };
59885
- };
59886
- var isRetryableError = (err, policy) => {
59887
- if (err instanceof APITimeoutError)
59888
- return policy.apiTimeoutError;
59889
- if (err instanceof APIConnectionError)
59890
- return policy.apiConnectionError;
59891
- return false;
59892
- };
59893
- var resolveLogLevel = (fromCode) => {
59894
- if (fromCode !== undefined)
59895
- return parseLogLevel(fromCode, "the `logLevel` option");
59896
- const fromEnv = readEnv(ENV.logLevel);
59897
- if (fromEnv !== undefined)
59898
- return parseLogLevel(fromEnv, ENV.logLevel);
59899
- return DEFAULT_LOG_LEVEL;
59900
- };
59901
- var stripTrailingSlashes = (url3) => url3.replace(/\/+$/, "");
59902
- var mergeHeaders = (...sources) => {
59903
- const entries = /* @__PURE__ */ new Map;
59904
- for (const source of sources)
59905
- for (const [name, value] of Object.entries(source))
59906
- if (value === undefined)
59907
- entries.delete(name.toLowerCase());
59908
- else
59909
- entries.set(name.toLowerCase(), [name, value]);
59910
- return Object.fromEntries(entries.values());
59911
- };
59912
- var bufferResponse = async (response, signal) => {
59913
- const reader = response.clone().body?.getReader();
59914
- if (!reader)
59915
- return;
59916
- const cancel = () => {
59917
- reader.cancel(signal.reason).catch(() => {});
59918
- response.body?.cancel(signal.reason).catch(() => {});
59919
- };
59920
- signal.addEventListener("abort", cancel, { once: true });
59921
- try {
59922
- if (signal.aborted)
59923
- cancel();
59924
- signal.throwIfAborted();
59925
- while (!(await reader.read()).done)
59926
- signal.throwIfAborted();
59927
- signal.throwIfAborted();
59928
- } finally {
59929
- signal.removeEventListener("abort", cancel);
59930
- reader.releaseLock();
59931
- }
59932
- };
59933
- var RUNTIME = describeRuntime();
59934
- var TypeSafeClient = class {
59935
- #apiKey;
59936
- baseURL;
59937
- defaultModel;
59938
- logLevel;
59939
- logger;
59940
- retry;
59941
- timeout;
59942
- defaultHeaders;
59943
- fetch;
59944
- models;
59945
- #requestCount = 0;
59946
- constructor(config2 = {}) {
59947
- if (isBrowser() && !config2.dangerouslyAllowBrowser)
59948
- refuseBrowser();
59949
- this.#apiKey = fromCodeOrEnv(config2.apiKey, ENV.apiKey) ?? missingApiKey();
59950
- this.baseURL = stripTrailingSlashes(fromCodeOrEnv(config2.baseURL, ENV.baseURL) ?? "https://api.typesafe.ai");
59951
- this.defaultModel = fromCodeOrEnv(config2.defaultModel, ENV.defaultModel) ?? "jev-latest";
59952
- this.logLevel = resolveLogLevel(config2.logLevel);
59953
- this.logger = withLevel(config2.logger ?? consoleLogger, this.logLevel);
59954
- this.retry = resolveRetryPolicy(DEFAULT_RETRY_POLICY, config2.retry);
59955
- this.timeout = assertPositiveMs("timeout", config2.timeout ?? 1e4);
59956
- this.defaultHeaders = { ...config2.defaultHeaders };
59957
- if (config2.fetch === undefined && typeof globalThis.fetch !== "function")
59958
- missingFetch();
59959
- this.fetch = config2.fetch ?? defaultFetch;
59960
- const transport = {
59961
- request: (method, path, options) => this.#request(method, path, options),
59962
- defaultModel: this.defaultModel
59963
- };
59964
- this.models = new Models(transport);
59965
- }
59966
- systemOne(request, options = {}) {
59967
- validateQuestions(request.questions);
59968
- const body = {
59969
- ...request,
59970
- model: request.model ?? this.defaultModel
59971
- };
59972
- return this.#request("POST", "/v1/systemone", {
59973
- ...options,
59974
- body
59975
- });
59459
+ // ../../node_modules/.bun/@nimit9+signet-ai@0.1.11+a8a356da5edd5fb9/node_modules/@nimit9/signet-ai/dist/jev.js
59460
+ var JEV_DEFAULT_MODEL = "jev-1.13.0";
59461
+ var JEV_DEFAULT_MIN_CONFIDENCE = 0.95;
59462
+ var JEV_DEFAULT_TIMEOUT_MS = 8000;
59463
+ var JEV_DEFAULT_BASE_URL = "https://api.typesafe.ai";
59464
+ function fallbackOf(q2, reason, extra = {}) {
59465
+ const d2 = { value: q2.fallback, confident: false, source: "fallback", reason };
59466
+ if (extra.confidence !== undefined)
59467
+ d2.confidence = extra.confidence;
59468
+ if (extra.answer !== undefined)
59469
+ d2.answer = extra.answer;
59470
+ if (extra.probability !== undefined)
59471
+ d2.probability = extra.probability;
59472
+ return d2;
59473
+ }
59474
+ function labelsOf(options) {
59475
+ return Array.isArray(options) ? [...options] : Object.keys(options);
59476
+ }
59477
+ function isUnit(n2) {
59478
+ return typeof n2 === "number" && Number.isFinite(n2) && n2 >= 0 && n2 <= 1;
59479
+ }
59480
+ function validQuestion(q2) {
59481
+ if (!q2 || typeof q2.question !== "string")
59482
+ return false;
59483
+ if (q2.type === "choice") {
59484
+ const labels = labelsOf(q2.options);
59485
+ return labels.length >= 1 && labels.length <= 255 && labels.includes(q2.fallback);
59486
+ }
59487
+ if (q2.type === "score") {
59488
+ return Array.isArray(q2.levels) && q2.levels.length >= 2 && q2.levels.length <= 10;
59489
+ }
59490
+ return q2.type === "noul";
59491
+ }
59492
+ function toWire(q2) {
59493
+ if (q2.type === "choice") {
59494
+ const criteria = Array.isArray(q2.options) ? Object.fromEntries(q2.options.map((l2) => [l2, null])) : q2.options;
59495
+ return { type: "choice", instructions: q2.question, criteria };
59496
+ }
59497
+ if (q2.type === "score")
59498
+ return { type: "score", instructions: q2.question, criteria: q2.levels };
59499
+ return { type: "noul", instructions: q2.question };
59500
+ }
59501
+ function judge(q2, raw, min) {
59502
+ const a2 = raw;
59503
+ if (!a2 || typeof a2 !== "object")
59504
+ return fallbackOf(q2, "invalid_response");
59505
+ if (q2.type === "noul") {
59506
+ const p2 = a2.noul;
59507
+ if (!isUnit(p2))
59508
+ return fallbackOf(q2, "invalid_response");
59509
+ const confidence2 = Math.max(p2, 1 - p2);
59510
+ const answer2 = p2 >= 0.5;
59511
+ if (confidence2 < min) {
59512
+ return fallbackOf(q2, "low_confidence", { confidence: confidence2, answer: answer2, probability: p2 });
59513
+ }
59514
+ return { value: answer2, confident: true, source: "jev", confidence: confidence2, probability: p2 };
59515
+ }
59516
+ const confidence = a2.confidence;
59517
+ if (!isUnit(confidence))
59518
+ return fallbackOf(q2, "invalid_response");
59519
+ let answer;
59520
+ if (q2.type === "choice") {
59521
+ if (typeof a2.choice !== "string" || !labelsOf(q2.options).includes(a2.choice)) {
59522
+ return fallbackOf(q2, "invalid_response", { confidence });
59523
+ }
59524
+ answer = a2.choice;
59525
+ } else {
59526
+ const s2 = a2.score;
59527
+ if (typeof s2 !== "number" || !Number.isFinite(s2) || s2 < 0 || s2 > q2.levels.length - 1) {
59528
+ return fallbackOf(q2, "invalid_response", { confidence });
59529
+ }
59530
+ answer = s2;
59976
59531
  }
59977
- #request(method, path, options = {}) {
59978
- const resolved = {
59979
- method,
59980
- path,
59981
- body: options.body,
59982
- headers: mergeHeaders(this.defaultHeaders, options.headers ?? {}),
59983
- signal: options.signal,
59984
- timeout: options.timeout === undefined ? this.timeout : assertPositiveMs("timeout", options.timeout),
59985
- retry: resolveRetryPolicy(this.retry, options.retry)
59986
- };
59987
- const tag = `#${++this.#requestCount} ${method} ${path}`;
59988
- return new APIPromise(this.fetchWithRetries(tag, resolved), async (res) => {
59989
- const parsed = await parseBody(res);
59990
- this.logger.debug(`${tag} <- body`, parsed);
59991
- return parsed;
59992
- });
59532
+ if (confidence < min)
59533
+ return fallbackOf(q2, "low_confidence", { confidence, answer });
59534
+ return { value: answer, confident: true, source: "jev", confidence };
59535
+ }
59536
+
59537
+ class Timeout {
59538
+ }
59539
+ function createJev(config2) {
59540
+ const apiKey = typeof config2.apiKey === "string" ? config2.apiKey.trim() : "";
59541
+ const model = config2.model ?? JEV_DEFAULT_MODEL;
59542
+ const floor = config2.minConfidence ?? JEV_DEFAULT_MIN_CONFIDENCE;
59543
+ const timeoutMs = config2.timeoutMs ?? JEV_DEFAULT_TIMEOUT_MS;
59544
+ const allowSensitive = config2.allowSensitive === true;
59545
+ const url3 = `${(config2.baseUrl ?? JEV_DEFAULT_BASE_URL).replace(/\/+$/, "")}/v1/systemone`;
59546
+ function emit(event) {
59547
+ if (!config2.onEvent)
59548
+ return;
59549
+ try {
59550
+ config2.onEvent(event);
59551
+ } catch {}
59993
59552
  }
59994
- async fetchWithRetries(tag, req) {
59995
- const url3 = `${this.baseURL}${req.path}`;
59996
- const headers = mergeHeaders(req.headers, {
59997
- Authorization: `Bearer ${this.#apiKey}`,
59998
- Accept: "application/json",
59999
- "User-Agent": `typesafe-sdk/${VERSION2}`,
60000
- "X-TypeSafe-SDK": `typesafe-sdk/${VERSION2}`,
60001
- "X-TypeSafe-Runtime": RUNTIME,
60002
- "Content-Type": req.body === undefined ? undefined : "application/json",
60003
- "X-TypeSafe-Retry-Count": undefined
60004
- });
60005
- const body = req.body === undefined ? undefined : JSON.stringify(req.body);
60006
- for (let attempt = 0;; attempt++) {
60007
- const retriesLeft = req.retry.maxRetries - attempt;
60008
- const attemptHeaders = attempt === 0 ? headers : {
60009
- ...headers,
60010
- "X-TypeSafe-Retry-Count": String(attempt)
59553
+ function finish(questions, decisions, meta3) {
59554
+ const durationMs = Date.now() - meta3.started;
59555
+ for (const [name, d2] of Object.entries(decisions)) {
59556
+ const event = {
59557
+ kind: questions[name].type,
59558
+ name,
59559
+ source: d2.source,
59560
+ sensitive: meta3.sensitive,
59561
+ model,
59562
+ durationMs
60011
59563
  };
60012
- this.logger.debug(`${tag} -> ${url3}`, {
60013
- headers: redactHeaders(attemptHeaders),
60014
- body: req.body
60015
- });
60016
- const started = Date.now();
60017
- let res;
60018
- try {
60019
- res = await this.attempt(tag, url3, {
60020
- method: req.method,
60021
- headers: attemptHeaders,
60022
- body
60023
- }, req);
60024
- } catch (err) {
60025
- if (err instanceof APIUserAbortError || retriesLeft <= 0)
60026
- throw err;
60027
- if (!isRetryableError(err, req.retry))
60028
- throw err;
60029
- await this.backOff(tag, attempt, retriesLeft, err.message, undefined, req);
60030
- continue;
60031
- }
60032
- const requestId = requestIdFrom(res.headers);
60033
- this.logger.info(`${tag} <- ${res.status} in ${Date.now() - started}ms${requestId ? ` (request ${requestId})` : ""}`);
60034
- if (res.ok)
60035
- return res;
60036
- const errorBody = await parseBody(res);
60037
- this.logger.debug(`${tag} <- error body`, errorBody);
60038
- const error62 = APIError.fromResponse(res.status, errorBody, res.headers);
60039
- if (retriesLeft <= 0 || !isRetryableStatus(res.status, req.retry))
60040
- throw error62;
60041
- await this.backOff(tag, attempt, retriesLeft, `${res.status}`, res.headers, req);
59564
+ if (d2.reason)
59565
+ event.reason = d2.reason;
59566
+ if (d2.confidence !== undefined)
59567
+ event.confidence = d2.confidence;
59568
+ if (meta3.status !== undefined && d2.reason === "http_error")
59569
+ event.status = meta3.status;
59570
+ emit(event);
60042
59571
  }
59572
+ return decisions;
60043
59573
  }
60044
- async attempt(tag, url3, init, { signal, timeout }) {
60045
- const controller = new AbortController;
60046
- const abortFromCaller = () => controller.abort(signal?.reason);
60047
- if (signal?.aborted)
60048
- abortFromCaller();
60049
- signal?.addEventListener("abort", abortFromCaller, { once: true });
60050
- let timedOut = false;
60051
- const timer = setTimeout(() => {
60052
- timedOut = true;
60053
- controller.abort();
60054
- }, timeout);
59574
+ async function run(questions, base) {
60055
59575
  const started = Date.now();
60056
- const elapsed = () => `${Date.now() - started}ms`;
59576
+ const sensitive = base.sensitive === true;
59577
+ const all2 = (reason, status2) => finish(questions, Object.fromEntries(Object.entries(questions).map(([n2, q2]) => [n2, fallbackOf(q2, reason)])), { sensitive, started, status: status2 });
59578
+ if (base.sensitive !== false && !allowSensitive)
59579
+ return all2("sensitive_not_allowed");
59580
+ if (!apiKey)
59581
+ return all2("no_key");
59582
+ const min = base.minConfidence ?? floor;
59583
+ const names = Object.keys(questions);
59584
+ if (!isUnit(min) || names.length === 0 || !names.every((n2) => validQuestion(questions[n2]))) {
59585
+ return all2("invalid_request");
59586
+ }
59587
+ if (base.signal?.aborted)
59588
+ return all2("aborted");
59589
+ const controller = new AbortController;
59590
+ const onAbort = () => controller.abort();
59591
+ base.signal?.addEventListener("abort", onAbort, { once: true });
59592
+ let timer;
59593
+ const timeout = new Promise((resolve) => {
59594
+ timer = setTimeout(() => {
59595
+ controller.abort();
59596
+ resolve(new Timeout);
59597
+ }, timeoutMs);
59598
+ });
59599
+ const doFetch = config2.fetch ?? ((u2, i2) => globalThis.fetch(u2, i2));
59600
+ let status;
60057
59601
  try {
60058
- const response = await this.fetch(url3, {
60059
- ...init,
60060
- signal: controller.signal
60061
- });
60062
- await bufferResponse(response, controller.signal);
60063
- return response;
59602
+ const request = (async () => {
59603
+ const res = await doFetch(url3, {
59604
+ method: "POST",
59605
+ headers: {
59606
+ Authorization: `Bearer ${apiKey}`,
59607
+ Accept: "application/json",
59608
+ "Content-Type": "application/json"
59609
+ },
59610
+ body: JSON.stringify({
59611
+ model,
59612
+ state: base.state,
59613
+ questions: Object.fromEntries(names.map((n2) => [n2, toWire(questions[n2])]))
59614
+ }),
59615
+ signal: controller.signal
59616
+ });
59617
+ status = res.status;
59618
+ if (!res.ok)
59619
+ return { ok: false };
59620
+ return { ok: true, body: await res.json() };
59621
+ })();
59622
+ const out = await Promise.race([request, timeout]);
59623
+ if (out instanceof Timeout) {
59624
+ request.catch(() => {});
59625
+ return all2("timeout");
59626
+ }
59627
+ if (!out.ok)
59628
+ return all2("http_error", status);
59629
+ const answers = out.body?.answers;
59630
+ if (!answers || typeof answers !== "object")
59631
+ return all2("invalid_response");
59632
+ return finish(questions, Object.fromEntries(names.map((n2) => [n2, judge(questions[n2], answers[n2], min)])), { sensitive, started });
60064
59633
  } catch (err) {
60065
- if (signal?.aborted) {
60066
- this.logger.info(`${tag} aborted by caller after ${elapsed()}`);
60067
- throw new APIUserAbortError(undefined, { cause: err });
60068
- }
60069
- if (timedOut) {
60070
- this.logger.info(`${tag} timed out after ${elapsed()}`);
60071
- throw new APITimeoutError(timeout, { cause: err });
60072
- }
60073
- this.logger.info(`${tag} connection error after ${elapsed()}`, err);
60074
- throw new APIConnectionError(err instanceof Error ? `Connection error: ${err.message}` : undefined, { cause: err });
59634
+ if (base.signal?.aborted)
59635
+ return all2("aborted");
59636
+ if (status !== undefined)
59637
+ return all2("invalid_response");
59638
+ return all2(err?.name === "TimeoutError" ? "timeout" : "network_error");
60075
59639
  } finally {
60076
59640
  clearTimeout(timer);
60077
- signal?.removeEventListener("abort", abortFromCaller);
59641
+ base.signal?.removeEventListener("abort", onAbort);
60078
59642
  }
60079
59643
  }
60080
- async backOff(tag, attempt, retriesLeft, reason, headers, { retry, signal }) {
60081
- const delay = retryDelayMs(attempt, headers, retry);
60082
- const nth = attempt + 1;
60083
- const total = attempt + retriesLeft;
60084
- this.logger.info(`${tag} retrying in ${delay}ms (retry ${nth}/${total}) after ${reason}`);
60085
- try {
60086
- await sleep3(delay, signal);
60087
- } catch (err) {
60088
- this.logger.info(`${tag} aborted by caller while waiting to retry`);
60089
- throw new APIUserAbortError(undefined, { cause: err });
60090
- }
59644
+ function baseOf(args) {
59645
+ return {
59646
+ state: args.state,
59647
+ sensitive: args.sensitive,
59648
+ minConfidence: args.minConfidence,
59649
+ signal: args.signal
59650
+ };
60091
59651
  }
60092
- };
60093
- var parseBody = async (res) => {
60094
- const text = await res.text();
60095
- if (text.length === 0)
60096
- return;
60097
- if ((res.headers.get("content-type") ?? "").includes("application/json"))
60098
- try {
60099
- return JSON.parse(text);
60100
- } catch {
60101
- return text;
59652
+ return {
59653
+ enabled: apiKey.length > 0,
59654
+ async choice(args) {
59655
+ const q2 = {
59656
+ type: "choice",
59657
+ question: args.question,
59658
+ options: args.options,
59659
+ fallback: args.fallback
59660
+ };
59661
+ const { result } = await run({ result: q2 }, baseOf(args));
59662
+ return result;
59663
+ },
59664
+ async score(args) {
59665
+ const q2 = {
59666
+ type: "score",
59667
+ question: args.question,
59668
+ levels: args.levels,
59669
+ fallback: args.fallback
59670
+ };
59671
+ const { result } = await run({ result: q2 }, baseOf(args));
59672
+ return result;
59673
+ },
59674
+ async noul(args) {
59675
+ const q2 = { type: "noul", question: args.question, fallback: args.fallback };
59676
+ const { result } = await run({ result: q2 }, baseOf(args));
59677
+ return result;
59678
+ },
59679
+ async batch(args) {
59680
+ return await run(args.questions, baseOf(args));
60102
59681
  }
60103
- try {
60104
- return JSON.parse(text);
60105
- } catch {
60106
- return text;
60107
- }
60108
- };
59682
+ };
59683
+ }
60109
59684
 
60110
59685
  // src/lib/jev-categorize.ts
60111
59686
  var JEV_MODEL = "jev-1.13.0";
@@ -60125,18 +59700,18 @@ function assertJevAllowed(crypto3, env2 = process.env) {
60125
59700
  throw new Error("JEV_API_KEY is not set — Jev categorization is off.");
60126
59701
  return key;
60127
59702
  }
60128
- function makeJevClassifier(apiKey) {
60129
- const client = new TypeSafeClient({ apiKey, timeout: TIMEOUT_MS });
60130
- return async (state, options) => {
60131
- const { answers } = await client.systemOne({
60132
- model: JEV_MODEL,
60133
- state,
60134
- questions: {
60135
- category: choice("Which spending category best fits this bank transaction?", options)
60136
- }
60137
- });
60138
- return { choice: answers.category.choice, confidence: answers.category.confidence };
60139
- };
59703
+ function jevAllowSensitive(crypto3, env2) {
59704
+ return crypto3 === undefined || env2.JEV_ALLOW_PRIVATE_MODE === "1";
59705
+ }
59706
+ function makeJev(apiKey, crypto3, env2 = process.env, fetchImpl) {
59707
+ return createJev({
59708
+ apiKey,
59709
+ model: JEV_MODEL,
59710
+ minConfidence: DEFAULT_MIN_CONFIDENCE,
59711
+ timeoutMs: TIMEOUT_MS,
59712
+ allowSensitive: jevAllowSensitive(crypto3, env2),
59713
+ ...fetchImpl ? { fetch: fetchImpl } : {}
59714
+ });
60140
59715
  }
60141
59716
  var UNSURE = "unsure";
60142
59717
  function optionsFor(type, index) {
@@ -60154,26 +59729,33 @@ function groupState(type, sample) {
60154
59729
  const dir = type === "credit" ? "Money received" : "Money paid out";
60155
59730
  return `${dir}. Bank narration: "${sample.slice(0, 80)}"`;
60156
59731
  }
60157
- async function jevCategorize(client, crypto3, classify, opts = {}) {
59732
+ async function jevCategorize(client, crypto3, jev, opts = {}) {
60158
59733
  assertPrivateModeAllowed(crypto3, opts.env);
60159
- const min = opts.minConfidence ?? DEFAULT_MIN_CONFIDENCE;
60160
59734
  const index = await loadCategoryIndex(client);
60161
59735
  const rows = await fetchUncategorized(client, crypto3, opts);
60162
59736
  const groups = groupRows(rows);
60163
- const unparsed = groups.filter((g3) => g3.pattern === UNPARSED).length;
60164
- const candidates = groups.filter((g3) => g3.pattern !== UNPARSED);
59737
+ const unparsed = groups.filter((g2) => g2.pattern === UNPARSED).length;
59738
+ const candidates = groups.filter((g2) => g2.pattern !== UNPARSED);
60165
59739
  let errors3 = 0;
60166
- const suggestions = await mapLimit(candidates, CONCURRENCY, async (g3) => {
60167
- try {
60168
- const options = optionsFor(g3.type, index);
60169
- const sample = g3.rows[0].description;
60170
- const text = crypto3 ? g3.pattern : sample;
60171
- const r2 = await classify(groupState(g3.type, text), options);
60172
- return r2.choice in options ? { g: g3, ...r2 } : null;
60173
- } catch {
60174
- errors3 += 1;
60175
- return null;
59740
+ const suggestions = await mapLimit(candidates, CONCURRENCY, async (g2) => {
59741
+ const options = optionsFor(g2.type, index);
59742
+ const sample = g2.rows[0].description;
59743
+ const text = crypto3 ? g2.pattern : sample;
59744
+ const d2 = await jev.choice({
59745
+ question: "Which spending category best fits this bank transaction?",
59746
+ options,
59747
+ fallback: UNSURE,
59748
+ state: groupState(g2.type, text),
59749
+ sensitive: true,
59750
+ minConfidence: opts.minConfidence
59751
+ });
59752
+ if (d2.confident)
59753
+ return { g: g2, choice: d2.value, confidence: d2.confidence, confident: true };
59754
+ if (d2.reason === "low_confidence" && d2.answer !== undefined) {
59755
+ return { g: g2, choice: d2.answer, confidence: d2.confidence ?? 0, confident: false };
60176
59756
  }
59757
+ errors3 += 1;
59758
+ return null;
60177
59759
  });
60178
59760
  const accepted = [];
60179
59761
  const review = [];
@@ -60181,7 +59763,7 @@ async function jevCategorize(client, crypto3, classify, opts = {}) {
60181
59763
  if (!s2)
60182
59764
  continue;
60183
59765
  const isTransfer = index.bySlug.get(s2.choice)?.type === "transfer";
60184
- if (s2.choice !== UNSURE && !isTransfer && s2.confidence >= min) {
59766
+ if (s2.confident && s2.choice !== UNSURE && !isTransfer) {
60185
59767
  accepted.push({
60186
59768
  pattern: s2.g.pattern,
60187
59769
  type: s2.g.type,
@@ -60230,7 +59812,8 @@ function jevTools(client, crypto3) {
60230
59812
  }),
60231
59813
  handler: async ({ startDate, endDate, minConfidence, dryRun }) => {
60232
59814
  const key = assertJevAllowed(crypto3);
60233
- const result = await jevCategorize(client, crypto3, makeJevClassifier(key), {
59815
+ const jev = makeJev(key, crypto3);
59816
+ const result = await jevCategorize(client, crypto3, jev, {
60234
59817
  startDate,
60235
59818
  endDate,
60236
59819
  minConfidence,
@@ -60268,15 +59851,7 @@ function settingsTools(client) {
60268
59851
  describe: { name: "", ownerLabels: "Owner slug → display name" },
60269
59852
  variants: { profile: profile.update, household: household.update }
60270
59853
  });
60271
- return [
60272
- get.tool,
60273
- update.tool,
60274
- get.alias("get_profile", "profile"),
60275
- get.alias("get_household", "household"),
60276
- get.alias("get_encryption_status", "encryption"),
60277
- update.alias("update_profile", "profile"),
60278
- update.alias("update_household", "household")
60279
- ];
59854
+ return [get.tool, update.tool];
60280
59855
  }
60281
59856
 
60282
59857
  // src/tools/statement-import.ts
@@ -60562,15 +60137,7 @@ function statementImportTools(client, crypto3) {
60562
60137
  })
60563
60138
  }
60564
60139
  });
60565
- return [
60566
- preview.tool,
60567
- commit.tool,
60568
- aliasTool("import_statement_pdf", pdfInput.extend({ confirm: exports_external.boolean().optional() }), "preview_import / import_statement", 'from: "pdf" (confirm:true → import_statement, else preview_import)', ({ confirm, ...args }) => confirm ? [commit.tool, { ...args, from: "pdf" }] : [preview.tool, { ...args, from: "pdf" }]),
60569
- preview.alias("import_csv_parse", "csv"),
60570
- commit.alias("import_csv_confirm", "csv"),
60571
- commit.alias("import_statement_batch", "rows"),
60572
- commit.alias("import_statement_file", "json_file")
60573
- ];
60140
+ return [preview.tool, commit.tool];
60574
60141
  }
60575
60142
 
60576
60143
  // src/registrations.ts
@@ -60715,7 +60282,7 @@ function registerResources(server, tools) {
60715
60282
  // package.json
60716
60283
  var package_default = {
60717
60284
  name: "paisa-mcp",
60718
- version: "0.2.0",
60285
+ version: "0.3.0",
60719
60286
  repository: {
60720
60287
  type: "git",
60721
60288
  url: "git+https://github.com/nimit9/paisa.git",
@@ -60742,13 +60309,14 @@ var package_default = {
60742
60309
  devDependencies: {
60743
60310
  "@modelcontextprotocol/client": "^2.1.0",
60744
60311
  "@modelcontextprotocol/server": "^2.1.0",
60312
+ "@nimit9/signet-ai": "^0.1.11",
60313
+ "@nimit9/signet-lib": "^0.1.14",
60745
60314
  "@nimit9/signet-server": "^0.2.2",
60746
60315
  "@paisa/parsers": "workspace:*",
60747
60316
  "@paisa/reconciliation": "workspace:*",
60748
60317
  "@paisa/types": "workspace:*",
60749
60318
  "@scure/bip39": "^2.2.0",
60750
60319
  "@types/bun": "^1.3.14",
60751
- "@typesafe-ai/sdk": "^0.6.0",
60752
60320
  axios: "^1.16.1",
60753
60321
  "hash-wasm": "^4.12.0",
60754
60322
  typescript: "^7.0.2",
@@ -60760,7 +60328,7 @@ var package_default = {
60760
60328
  };
60761
60329
 
60762
60330
  // src/version.ts
60763
- var VERSION3 = package_default.version;
60331
+ var VERSION2 = package_default.version;
60764
60332
 
60765
60333
  // src/server.ts
60766
60334
  function paisaErrorResult(err) {
@@ -60772,31 +60340,18 @@ function paisaErrorResult(err) {
60772
60340
  function buildServer(client, crypto3) {
60773
60341
  const tools = applyAnnotations(REGISTRATIONS.flatMap((group) => group.tools(client, crypto3)));
60774
60342
  for (const t2 of tools)
60775
- if (t2.input && !isAlias(t2))
60343
+ if (t2.input)
60776
60344
  withCompactJsonSchema(t2.input);
60777
60345
  const server = createMcpServer({
60778
60346
  name: "paisa",
60779
- version: VERSION3,
60347
+ version: VERSION2,
60780
60348
  tools,
60781
60349
  errorResult: paisaErrorResult
60782
60350
  });
60783
- hideFromToolsList(server, new Set(tools.filter(isAlias).map((t2) => t2.name)));
60784
60351
  registerResources(server, tools);
60785
60352
  registerPrompts(server);
60786
60353
  return server;
60787
60354
  }
60788
- function hideFromToolsList(server, hidden) {
60789
- if (hidden.size === 0)
60790
- return;
60791
- const inner = server.server;
60792
- const list = inner._getRequestHandler("tools/list");
60793
- if (!list)
60794
- throw new Error("MCP SDK: no tools/list handler to wrap (aliases would be listed)");
60795
- server.server.setRequestHandler("tools/list", async (request, ctx) => {
60796
- const result = await list(request, ctx);
60797
- return { ...result, tools: result.tools.filter((t2) => !hidden.has(t2.name)) };
60798
- });
60799
- }
60800
60355
 
60801
60356
  // src/index.ts
60802
60357
  async function main() {
@@ -60819,5 +60374,5 @@ main().catch((err) => {
60819
60374
  process.exit(1);
60820
60375
  });
60821
60376
 
60822
- //# debugId=1E3042577A7AFC5F64756E2164756E21
60377
+ //# debugId=C64445D8B55EDCFA64756E2164756E21
60823
60378
  //# sourceMappingURL=index.js.map