@squadbase/vite-server 0.1.17-dev.a9ddcfa → 0.1.17-dev.e4768d1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/cli/index.js +8941 -3700
  2. package/dist/connectors/airtable-oauth.js +87 -23
  3. package/dist/connectors/airtable.js +130 -23
  4. package/dist/connectors/amplitude.js +47 -23
  5. package/dist/connectors/anthropic.js +41 -17
  6. package/dist/connectors/asana.js +76 -25
  7. package/dist/connectors/attio.js +69 -28
  8. package/dist/connectors/aws-billing.js +47 -23
  9. package/dist/connectors/azure-sql.js +322 -25
  10. package/dist/connectors/backlog-api-key.js +79 -30
  11. package/dist/connectors/clickup.js +89 -25
  12. package/dist/connectors/cosmosdb.js +51 -27
  13. package/dist/connectors/customerio.js +47 -23
  14. package/dist/connectors/dbt.js +725 -40
  15. package/dist/connectors/freshdesk.js +121 -23
  16. package/dist/connectors/freshsales.js +47 -23
  17. package/dist/connectors/freshservice.js +47 -23
  18. package/dist/connectors/gamma.js +54 -30
  19. package/dist/connectors/gemini.js +41 -17
  20. package/dist/connectors/github.js +51 -27
  21. package/dist/connectors/gmail-oauth.js +42 -23
  22. package/dist/connectors/gmail.js +43 -19
  23. package/dist/connectors/google-ads.js +47 -23
  24. package/dist/connectors/google-analytics-oauth.js +191 -40
  25. package/dist/connectors/google-analytics.js +529 -111
  26. package/dist/connectors/google-audit-log.js +43 -19
  27. package/dist/connectors/google-calendar-oauth.js +100 -30
  28. package/dist/connectors/google-calendar.js +100 -26
  29. package/dist/connectors/google-docs.js +42 -23
  30. package/dist/connectors/google-drive.js +64 -23
  31. package/dist/connectors/google-search-console-oauth.js +165 -32
  32. package/dist/connectors/google-sheets.js +142 -199
  33. package/dist/connectors/google-slides.js +42 -23
  34. package/dist/connectors/grafana.js +84 -25
  35. package/dist/connectors/hackernews.d.ts +5 -0
  36. package/dist/connectors/hackernews.js +909 -0
  37. package/dist/connectors/hubspot-oauth.js +73 -22
  38. package/dist/connectors/hubspot.js +64 -24
  39. package/dist/connectors/influxdb.js +47 -23
  40. package/dist/connectors/intercom-oauth.js +104 -25
  41. package/dist/connectors/intercom.js +51 -27
  42. package/dist/connectors/jdbc.js +76 -25
  43. package/dist/connectors/jira-api-key.js +107 -26
  44. package/dist/connectors/kintone-api-token.js +105 -33
  45. package/dist/connectors/kintone.js +182 -26
  46. package/dist/connectors/linear.js +93 -27
  47. package/dist/connectors/linkedin-ads.js +80 -29
  48. package/dist/connectors/mailchimp-oauth.js +45 -21
  49. package/dist/connectors/mailchimp.js +45 -21
  50. package/dist/connectors/meta-ads-oauth.js +72 -29
  51. package/dist/connectors/meta-ads.js +74 -29
  52. package/dist/connectors/mixpanel.js +47 -23
  53. package/dist/connectors/monday.js +48 -24
  54. package/dist/connectors/mongodb.js +47 -23
  55. package/dist/connectors/notion-oauth.js +92 -24
  56. package/dist/connectors/notion.js +144 -26
  57. package/dist/connectors/openai.js +41 -17
  58. package/dist/connectors/oracle.js +316 -26
  59. package/dist/connectors/outlook-oauth.js +53 -34
  60. package/dist/connectors/powerbi-oauth.js +45 -26
  61. package/dist/connectors/salesforce.js +150 -24
  62. package/dist/connectors/semrush.js +45 -21
  63. package/dist/connectors/sentry.js +75 -25
  64. package/dist/connectors/shopify-oauth.js +75 -23
  65. package/dist/connectors/shopify.js +47 -23
  66. package/dist/connectors/sqlserver.js +322 -25
  67. package/dist/connectors/stripe-api-key.js +105 -30
  68. package/dist/connectors/stripe-oauth.js +102 -32
  69. package/dist/connectors/supabase.js +315 -21
  70. package/dist/connectors/tableau.js +54 -30
  71. package/dist/connectors/tiktok-ads.js +76 -31
  72. package/dist/connectors/wix-store.js +47 -23
  73. package/dist/connectors/x.d.ts +5 -0
  74. package/dist/connectors/x.js +951 -0
  75. package/dist/connectors/zendesk-oauth.js +87 -25
  76. package/dist/connectors/zendesk.js +51 -27
  77. package/dist/index.js +9005 -3709
  78. package/dist/main.js +9005 -3709
  79. package/dist/vite-plugin.js +8939 -3698
  80. package/package.json +12 -4
@@ -1,7 +1,12 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
- var __esm = (fn, res) => function __init() {
4
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
3
+ var __esm = (fn, res, err) => function __init() {
4
+ if (err) throw err[0];
5
+ try {
6
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
+ } catch (e) {
8
+ throw err = [e], e;
9
+ }
5
10
  };
6
11
  var __export = (target, all) => {
7
12
  for (var name in all)
@@ -308,7 +313,7 @@ async function runMssqlQuery(parsed, sql, options = {}) {
308
313
  try {
309
314
  const result = await pool.request().query(sql);
310
315
  const recordset = result.recordset ?? [];
311
- return { rows: recordset };
316
+ return { rows: recordset, rowsAffected: result.rowsAffected ?? [] };
312
317
  } finally {
313
318
  await pool.close();
314
319
  }
@@ -474,6 +479,15 @@ var ConnectorPlugin = class _ConnectorPlugin {
474
479
  * `runSetupFlow` from `setup-flow.ts`.
475
480
  */
476
481
  setup;
482
+ /**
483
+ * 統一 introspection。SQL DB の `information_schema` / `SHOW` / `DESCRIBE` や SaaS の
484
+ * メタデータ API といった取得経路の差を吸収し、tables / columns / PK / FK を共通型
485
+ * {@link IntrospectedSchema} へ正規化して返す。取得経路は {@link IntrospectContext} で
486
+ * 抽象化され、SQL DB は `ctx.query`、SaaS は `ctx.proxyFetch` + `ctx.params` を使う。
487
+ * `ctx.profile === true` のときは L2 プロファイル(行数・NULL 率等)も best-effort で埋める。
488
+ * coding-agent の `DataContextIndex` がデータ地図を構築する際に使う。
489
+ */
490
+ introspect;
477
491
  /**
478
492
  * Opt-out of the default "verify before save" behavior on connection
479
493
  * creation. The backend invokes `checkConnection` synchronously while
@@ -488,6 +502,14 @@ var ConnectorPlugin = class _ConnectorPlugin {
488
502
  * the default verify-on-create behavior without opt-in.
489
503
  */
490
504
  skipConnectionCheckOnCreate;
505
+ /**
506
+ * 決定論的な「立ち上げ survey」レシピ(ルールベース prewarm 基盤)。実装した connector は、LLM を使わずに
507
+ * read-only で自分を survey する probe 列(テーブル/列メタデータ → 小サンプル)を宣言する。coding-agent の
508
+ * recon driver がこれを読み、connector ツールの `execute` を直接呼んで結果を seed にする。未実装の connector は
509
+ * driver 側で safely skip される(その connection は listConnections のみ seed)。標準 `information_schema` を
510
+ * 持つ SQL connector は `makeStandardSqlSurveyProbes` を使える。**probe は必ず read-only**。
511
+ */
512
+ surveyProbes;
491
513
  constructor(config) {
492
514
  this.slug = config.slug;
493
515
  this.authType = config.authType;
@@ -505,7 +527,9 @@ var ConnectorPlugin = class _ConnectorPlugin {
505
527
  this.query = config.query;
506
528
  this.checkConnection = config.checkConnection;
507
529
  this.setup = config.setup;
530
+ this.introspect = config.introspect;
508
531
  this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
532
+ this.surveyProbes = config.surveyProbes;
509
533
  }
510
534
  get connectorKey() {
511
535
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -513,7 +537,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
513
537
  /**
514
538
  * Create tools for connections that belong to this connector.
515
539
  * Filters connections by connectorKey internally.
516
- * Returns tools keyed as `${connectorKey}_${toolName}`.
540
+ * Returns tools keyed as `connector_${connectorKey}_${toolName}`.
517
541
  */
518
542
  createTools(connections, config, opts) {
519
543
  const myConnections = connections.filter(
@@ -523,7 +547,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
523
547
  for (const t of Object.values(this.tools)) {
524
548
  const tool = t.createTool(myConnections, config);
525
549
  const originalToModelOutput = tool.toModelOutput;
526
- result[`${this.connectorKey}_${t.name}`] = {
550
+ result[`connector_${this.connectorKey}_${t.name}`] = {
527
551
  ...tool,
528
552
  toModelOutput: async (options) => {
529
553
  if (!originalToModelOutput) {
@@ -543,25 +567,25 @@ var ConnectorPlugin = class _ConnectorPlugin {
543
567
  if (authType) return `${slug}-${authType}`;
544
568
  const LEGACY_NULL_AUTH_TYPE_MAP = {
545
569
  // user-password
546
- "postgresql": "user-password",
547
- "mysql": "user-password",
548
- "clickhouse": "user-password",
549
- "kintone": "user-password",
570
+ postgresql: "user-password",
571
+ mysql: "user-password",
572
+ clickhouse: "user-password",
573
+ kintone: "user-password",
550
574
  "squadbase-db": "user-password",
551
575
  // service-account
552
- "snowflake": "service-account",
553
- "bigquery": "service-account",
576
+ snowflake: "service-account",
577
+ bigquery: "service-account",
554
578
  "google-analytics": "service-account",
555
579
  "google-calendar": "service-account",
556
580
  "aws-athena": "service-account",
557
- "redshift": "service-account",
581
+ redshift: "service-account",
558
582
  // api-key
559
- "databricks": "api-key",
560
- "dbt": "api-key",
561
- "airtable": "api-key",
562
- "openai": "api-key",
563
- "gemini": "api-key",
564
- "anthropic": "api-key",
583
+ databricks: "api-key",
584
+ dbt: "api-key",
585
+ airtable: "api-key",
586
+ openai: "api-key",
587
+ gemini: "api-key",
588
+ anthropic: "api-key",
565
589
  "wix-store": "api-key"
566
590
  };
567
591
  const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
@@ -570,6 +594,84 @@ var ConnectorPlugin = class _ConnectorPlugin {
570
594
  }
571
595
  };
572
596
 
597
+ // ../connectors/src/survey-probe.ts
598
+ function rowsOf(output) {
599
+ if (!output || typeof output !== "object") return [];
600
+ const o = output;
601
+ if (o.success === false) return [];
602
+ return Array.isArray(o.rows) ? o.rows : [];
603
+ }
604
+ function pickString(row, candidates) {
605
+ for (const key of candidates) {
606
+ const v = row[key] ?? row[key.toUpperCase()] ?? row[key.toLowerCase()];
607
+ if (typeof v === "string" && v.length > 0) return v;
608
+ }
609
+ return void 0;
610
+ }
611
+ var TABLE_NAME_FIELDS = [
612
+ "table_name",
613
+ "name",
614
+ "tableName",
615
+ "tab_name",
616
+ "Table",
617
+ "table"
618
+ ];
619
+ function makeQuoteIdent(opts) {
620
+ if (opts.bracket) {
621
+ return (name) => `[${name.replaceAll("]", "]]")}]`;
622
+ }
623
+ const q = opts.quote ?? '"';
624
+ return (name) => `${q}${name.replaceAll(q, q + q)}${q}`;
625
+ }
626
+ function sampleSql(ref, limit) {
627
+ return `SELECT * FROM (SELECT * FROM ${ref}) AS _sq LIMIT ${limit}`;
628
+ }
629
+ function distinctTables(prior, max) {
630
+ const names = [];
631
+ const seen = /* @__PURE__ */ new Set();
632
+ for (const row of rowsOf(prior[0]?.output)) {
633
+ const name = pickString(row, TABLE_NAME_FIELDS);
634
+ if (!name || seen.has(name)) continue;
635
+ seen.add(name);
636
+ names.push(name);
637
+ if (names.length >= max) break;
638
+ }
639
+ return names;
640
+ }
641
+ function makeStandardSqlSurveyProbes(opts) {
642
+ const queryTool = opts.queryTool ?? "executeQuery";
643
+ const sampleLimit = opts.sampleLimit ?? 5;
644
+ const maxSampleTables = opts.maxSampleTables ?? 4;
645
+ const quoteIdent = makeQuoteIdent(opts);
646
+ const whereSchema = opts.schemaLiteral ? ` WHERE table_schema = '${opts.schemaLiteral.replaceAll("'", "''")}'` : opts.schemaExpr ? ` WHERE table_schema = ${opts.schemaExpr}` : "";
647
+ return (_connectionId, prior) => {
648
+ if (prior.length === 0) {
649
+ return [
650
+ {
651
+ tool: queryTool,
652
+ input: {
653
+ toolUseIntent: "Survey table/column metadata",
654
+ sql: `SELECT table_name, column_name, data_type FROM information_schema.columns${whereSchema} ORDER BY table_name, ordinal_position LIMIT 1000`
655
+ }
656
+ }
657
+ ];
658
+ }
659
+ if (prior.length === 1) {
660
+ return distinctTables(prior, maxSampleTables).map((name) => {
661
+ const ref = opts.schemaLiteral ? `${quoteIdent(opts.schemaLiteral)}.${quoteIdent(name)}` : quoteIdent(name);
662
+ return {
663
+ tool: queryTool,
664
+ input: {
665
+ toolUseIntent: `Sample ${name}`,
666
+ sql: sampleSql(ref, sampleLimit)
667
+ }
668
+ };
669
+ });
670
+ }
671
+ return [];
672
+ };
673
+ }
674
+
573
675
  // ../connectors/src/setup-flow.ts
574
676
  async function runSetupFlow(flow, params, ctx, config) {
575
677
  const runtime = {
@@ -640,6 +742,55 @@ async function resolveSetupSelection(params) {
640
742
  return resolved.slice(0, limit);
641
743
  }
642
744
 
745
+ // ../connectors/src/introspect-concurrency.ts
746
+ async function mapWithConcurrency(items, limit, fn) {
747
+ const results = new Array(items.length);
748
+ let next = 0;
749
+ const workers = Array.from(
750
+ { length: Math.min(Math.max(limit, 1), items.length) },
751
+ async () => {
752
+ for (; ; ) {
753
+ const i = next++;
754
+ if (i >= items.length) return;
755
+ results[i] = await fn(items[i]);
756
+ }
757
+ }
758
+ );
759
+ await Promise.all(workers);
760
+ return results;
761
+ }
762
+
763
+ // ../connectors/src/introspect-profile.ts
764
+ var DEFAULT_MAX_TABLES = 200;
765
+ var DEFAULT_CONCURRENCY = 5;
766
+ var quoteBracket = (schema, name) => `[${schema.replace(/\]/g, "]]")}].[${name.replace(/\]/g, "]]")}]`;
767
+ async function withRowCounts(ctx, schemaPromise, quoteRef, opts = {}) {
768
+ const schema = await schemaPromise;
769
+ if (!ctx.profile || !ctx.query) return schema;
770
+ return attachRowCounts(ctx.query, schema, quoteRef, opts);
771
+ }
772
+ async function attachRowCounts(run, schema, quoteRef, opts = {}) {
773
+ const targets = schema.tables.slice(0, opts.maxTables ?? DEFAULT_MAX_TABLES);
774
+ await mapWithConcurrency(
775
+ targets,
776
+ opts.concurrency ?? DEFAULT_CONCURRENCY,
777
+ async (table) => {
778
+ try {
779
+ const { rows } = await run(
780
+ `SELECT COUNT(*) AS row_count FROM ${quoteRef(table.schema, table.name)}`
781
+ );
782
+ const first = rows[0] ? Object.values(rows[0])[0] : void 0;
783
+ const rowCount = Number(first);
784
+ if (Number.isFinite(rowCount)) {
785
+ table.profile = { ...table.profile ?? {}, rowCount };
786
+ }
787
+ } catch {
788
+ }
789
+ }
790
+ );
791
+ return schema;
792
+ }
793
+
643
794
  // ../connectors/src/auth-types.ts
644
795
  var AUTH_TYPES = {
645
796
  OAUTH: "oauth",
@@ -650,6 +801,69 @@ var AUTH_TYPES = {
650
801
  USER_PASSWORD: "user-password"
651
802
  };
652
803
 
804
+ // ../connectors/src/introspect-information-schema.ts
805
+ function pickCI(row, key) {
806
+ if (key in row) return String(row[key] ?? "");
807
+ const lower = key.toLowerCase();
808
+ for (const k of Object.keys(row)) {
809
+ if (k.toLowerCase() === lower) return String(row[k] ?? "");
810
+ }
811
+ return "";
812
+ }
813
+ function assembleIntrospectedSchema(input) {
814
+ const { colRows, pkRows = [], fkRows = [] } = input;
815
+ const pkSet = /* @__PURE__ */ new Set();
816
+ for (const r of pkRows) {
817
+ pkSet.add(
818
+ `${pickCI(r, "table_schema")}.${pickCI(r, "table_name")}.${pickCI(r, "column_name")}`
819
+ );
820
+ }
821
+ const fkMap = /* @__PURE__ */ new Map();
822
+ for (const r of fkRows) {
823
+ fkMap.set(
824
+ `${pickCI(r, "table_schema")}.${pickCI(r, "table_name")}.${pickCI(r, "column_name")}`,
825
+ {
826
+ schema: pickCI(r, "foreign_table_schema"),
827
+ table: pickCI(r, "foreign_table_name"),
828
+ column: pickCI(r, "foreign_column_name")
829
+ }
830
+ );
831
+ }
832
+ const tableMap = /* @__PURE__ */ new Map();
833
+ for (const r of colRows) {
834
+ const schema = pickCI(r, "table_schema");
835
+ const name = pickCI(r, "table_name");
836
+ const key = `${schema}.${name}`;
837
+ let table = tableMap.get(key);
838
+ if (!table) {
839
+ table = {
840
+ schema,
841
+ name,
842
+ type: pickCI(r, "table_type").toUpperCase() === "VIEW" ? "view" : "table",
843
+ columns: []
844
+ };
845
+ tableMap.set(key, table);
846
+ }
847
+ const colKey = `${schema}.${name}.${pickCI(r, "column_name")}`;
848
+ const column = {
849
+ name: pickCI(r, "column_name"),
850
+ dataType: pickCI(r, "data_type"),
851
+ nullable: pickCI(r, "is_nullable").toUpperCase() === "YES"
852
+ };
853
+ if (pkSet.has(colKey)) column.isPrimaryKey = true;
854
+ const fk = fkMap.get(colKey);
855
+ if (fk) column.foreignKey = fk;
856
+ table.columns.push(column);
857
+ }
858
+ return { tables: [...tableMap.values()] };
859
+ }
860
+
861
+ // ../connectors/src/lib/sql-dml.ts
862
+ function isDmlStatement(sql) {
863
+ const stripped = sql.replace(/^(\s*(--[^\n]*\n|\/\*[\s\S]*?\*\/))+/, "").trimStart();
864
+ return /^(insert|update|delete|merge)\b/i.test(stripped);
865
+ }
866
+
653
867
  // ../connectors/src/lib/unwrap-sample-limit.ts
654
868
  var STRICT_WRAPPER_RE = /^\s*SELECT\s+\*\s+FROM\s+\(([\s\S]+)\)\s+AS\s+\w+\s+LIMIT\s+(\d+)\s*;?\s*$/i;
655
869
  var TRAILING_LIMIT_RE = /\s+LIMIT\s+(\d+)\s*;?\s*$/i;
@@ -756,6 +970,28 @@ function buildFlow(options) {
756
970
  fetchAll: () => fetchTableNames(rt.params, schema),
757
971
  limit: SQLSERVER_SETUP_MAX_TABLES
758
972
  });
973
+ let rowCounts = /* @__PURE__ */ new Map();
974
+ try {
975
+ const countRows = await runSqlServerSetupQuery(
976
+ rt.params,
977
+ `SELECT t.TABLE_NAME, SUM(p.rows) AS row_count
978
+ FROM INFORMATION_SCHEMA.TABLES t
979
+ JOIN sys.partitions p
980
+ ON OBJECT_ID(t.TABLE_SCHEMA + '.' + t.TABLE_NAME) = p.object_id
981
+ AND p.index_id IN (0, 1)
982
+ WHERE t.TABLE_SCHEMA = ${quoteLiteral(schema)}
983
+ AND t.TABLE_TYPE IN ('BASE TABLE', 'VIEW')
984
+ GROUP BY t.TABLE_NAME`,
985
+ forceEncrypt
986
+ );
987
+ rowCounts = new Map(
988
+ countRows.map((r) => [
989
+ String(r["TABLE_NAME"] ?? ""),
990
+ Number(r["row_count"] ?? 0)
991
+ ])
992
+ );
993
+ } catch {
994
+ }
759
995
  const sections = [
760
996
  `## ${connectorName}`,
761
997
  "",
@@ -772,7 +1008,9 @@ function buildFlow(options) {
772
1008
  ORDER BY ORDINAL_POSITION`,
773
1009
  forceEncrypt
774
1010
  );
775
- sections.push(`#### Table: ${table}`, "");
1011
+ const rowCount = rowCounts.get(table);
1012
+ const heading = typeof rowCount === "number" ? `#### Table: ${table} (~${rowCount.toLocaleString()} rows)` : `#### Table: ${table}`;
1013
+ sections.push(heading, "");
776
1014
  sections.push("| Column | Type | Nullable | Default |");
777
1015
  sections.push("|--------|------|----------|---------|");
778
1016
  for (const c of cols) {
@@ -798,6 +1036,52 @@ var sqlserverSetupFlow = createSqlServerSetupFlow({
798
1036
  forceEncrypt: false
799
1037
  });
800
1038
 
1039
+ // ../connectors/src/connectors/sqlserver/introspect.ts
1040
+ async function introspectMssql(run) {
1041
+ const [{ rows: colRows }, { rows: pkRows }, { rows: fkRows }] = await Promise.all([
1042
+ // 1) 全カラム(型 / nullable)+ テーブル種別(BASE TABLE / VIEW)
1043
+ run(
1044
+ `SELECT c.TABLE_SCHEMA AS table_schema, c.TABLE_NAME AS table_name,
1045
+ c.COLUMN_NAME AS column_name, c.DATA_TYPE AS data_type,
1046
+ c.IS_NULLABLE AS is_nullable, c.ORDINAL_POSITION AS ordinal_position,
1047
+ t.TABLE_TYPE AS table_type
1048
+ FROM INFORMATION_SCHEMA.COLUMNS c
1049
+ JOIN INFORMATION_SCHEMA.TABLES t
1050
+ ON t.TABLE_SCHEMA = c.TABLE_SCHEMA AND t.TABLE_NAME = c.TABLE_NAME
1051
+ WHERE c.TABLE_SCHEMA NOT IN ('sys', 'INFORMATION_SCHEMA')
1052
+ ORDER BY c.TABLE_SCHEMA, c.TABLE_NAME, c.ORDINAL_POSITION`
1053
+ ),
1054
+ // 2) 主キー
1055
+ run(
1056
+ `SELECT tc.TABLE_SCHEMA AS table_schema, tc.TABLE_NAME AS table_name,
1057
+ kcu.COLUMN_NAME AS column_name
1058
+ FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
1059
+ JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
1060
+ ON kcu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
1061
+ AND kcu.TABLE_SCHEMA = tc.TABLE_SCHEMA
1062
+ AND kcu.TABLE_NAME = tc.TABLE_NAME
1063
+ WHERE tc.CONSTRAINT_TYPE = 'PRIMARY KEY'
1064
+ AND tc.TABLE_SCHEMA NOT IN ('sys', 'INFORMATION_SCHEMA')`
1065
+ ),
1066
+ // 3) 外部キー(参照元列 → 参照先列)。sys カタログで複合 FK も 1:1 に解決する。
1067
+ run(
1068
+ `SELECT sch.name AS table_schema, tab.name AS table_name, col.name AS column_name,
1069
+ rsch.name AS foreign_table_schema, rtab.name AS foreign_table_name,
1070
+ rcol.name AS foreign_column_name
1071
+ FROM sys.foreign_key_columns fkc
1072
+ JOIN sys.tables tab ON tab.object_id = fkc.parent_object_id
1073
+ JOIN sys.schemas sch ON sch.schema_id = tab.schema_id
1074
+ JOIN sys.columns col ON col.object_id = fkc.parent_object_id
1075
+ AND col.column_id = fkc.parent_column_id
1076
+ JOIN sys.tables rtab ON rtab.object_id = fkc.referenced_object_id
1077
+ JOIN sys.schemas rsch ON rsch.schema_id = rtab.schema_id
1078
+ JOIN sys.columns rcol ON rcol.object_id = fkc.referenced_object_id
1079
+ AND rcol.column_id = fkc.referenced_column_id`
1080
+ )
1081
+ ]);
1082
+ return assembleIntrospectedSchema({ colRows, pkRows, fkRows });
1083
+ }
1084
+
801
1085
  // ../connectors/src/connectors/azure-sql/index.ts
802
1086
  init_mssql_runner();
803
1087
  init_utils();
@@ -805,11 +1089,11 @@ init_utils();
805
1089
  // ../connectors/src/connectors/azure-sql/setup.ts
806
1090
  var azureSqlOnboarding = new ConnectorOnboarding({
807
1091
  dataOverviewInstructions: {
808
- en: `1. Use azure-sql_executeQuery to confirm the database flavor: \`SELECT @@VERSION\` (Azure SQL returns "Microsoft SQL Azure \u2026")
1092
+ en: `1. Use connector_azure-sql_executeQuery to confirm the database flavor: \`SELECT @@VERSION\` (Azure SQL returns "Microsoft SQL Azure \u2026")
809
1093
  2. List user tables: \`SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA NOT IN ('sys', 'INFORMATION_SCHEMA')\`
810
1094
  3. For key tables, fetch column info: \`SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'xxx'\`
811
1095
  4. Sample up to 3 tables. Azure SQL is T-SQL, so use \`TOP\` rather than \`LIMIT\`: \`SELECT TOP 5 * FROM <schema>.<table_name>\``,
812
- ja: `1. azure-sql_executeQuery \u3067\u30D5\u30EC\u30FC\u30D0\u30FC\u3092\u78BA\u8A8D: \`SELECT @@VERSION\`\uFF08Azure SQL \u306F "Microsoft SQL Azure \u2026" \u3092\u8FD4\u3057\u307E\u3059\uFF09
1096
+ ja: `1. connector_azure-sql_executeQuery \u3067\u30D5\u30EC\u30FC\u30D0\u30FC\u3092\u78BA\u8A8D: \`SELECT @@VERSION\`\uFF08Azure SQL \u306F "Microsoft SQL Azure \u2026" \u3092\u8FD4\u3057\u307E\u3059\uFF09
813
1097
  2. \u30E6\u30FC\u30B6\u30FC\u30C6\u30FC\u30D6\u30EB\u4E00\u89A7: \`SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA NOT IN ('sys', 'INFORMATION_SCHEMA')\`
814
1098
  3. \u4E3B\u8981\u30C6\u30FC\u30D6\u30EB\u306E\u30AB\u30E9\u30E0\u60C5\u5831: \`SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'xxx'\`
815
1099
  4. \u5FC5\u8981\u306B\u5FDC\u3058\u3066\u6700\u59273\u30C6\u30FC\u30D6\u30EB\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u3002Azure SQL \u306F T-SQL \u306E\u305F\u3081 \`LIMIT\` \u3067\u306F\u306A\u304F \`TOP\` \u3092\u4F7F\u7528: \`SELECT TOP 5 * FROM <schema>.<table_name>\``
@@ -841,6 +1125,9 @@ var outputSchema = z.discriminatedUnion("success", [
841
1125
  z.object({
842
1126
  success: z.literal(true),
843
1127
  rowCount: z.number(),
1128
+ rowsAffected: z.number().optional().describe(
1129
+ "Affected rows for INSERT/UPDATE/DELETE; undefined for SELECT"
1130
+ ),
844
1131
  truncated: z.boolean(),
845
1132
  rows: z.array(z.record(z.string(), z.unknown()))
846
1133
  }),
@@ -854,7 +1141,8 @@ var executeQueryTool = new ConnectorTool({
854
1141
  description: `Execute a T-SQL query against Azure SQL Database. Returns up to ${MAX_ROWS} rows.
855
1142
  Use for: schema exploration via \`INFORMATION_SCHEMA\`, data sampling, and analytical queries.
856
1143
  Azure SQL is T-SQL: use \`TOP n\` instead of \`LIMIT n\`. Identifiers can be wrapped in square brackets.
857
- Avoid loading large amounts of data; always include \`TOP\` in queries.`,
1144
+ Avoid loading large amounts of data; always include \`TOP\` in queries.
1145
+ For INSERT/UPDATE/DELETE, \`rowCount\` is 0 and \`rows\` is empty (rowCount counts returned rows, not affected rows) \u2014 this is normal, not a failure; check \`rowsAffected\` for the number of affected rows.`,
858
1146
  inputSchema,
859
1147
  outputSchema,
860
1148
  async execute({ connectionId, sql }, connections) {
@@ -881,7 +1169,7 @@ Avoid loading large amounts of data; always include \`TOP\` in queries.`,
881
1169
  };
882
1170
  }
883
1171
  try {
884
- const { rows } = await runMssqlQuery(parsed, sql, {
1172
+ const { rows, rowsAffected } = await runMssqlQuery(parsed, sql, {
885
1173
  forceEncrypt: true,
886
1174
  tunnelParams: connectionParamsToRecord(connection2)
887
1175
  });
@@ -889,6 +1177,9 @@ Avoid loading large amounts of data; always include \`TOP\` in queries.`,
889
1177
  return {
890
1178
  success: true,
891
1179
  rowCount: Math.min(rows.length, MAX_ROWS),
1180
+ // tedious counts SELECT result rows in rowsAffected too, so only
1181
+ // report it for DML. Multi-statement batches are summed.
1182
+ rowsAffected: isDmlStatement(sql) ? rowsAffected.reduce((sum, n) => sum + n, 0) : void 0,
892
1183
  truncated,
893
1184
  rows: rows.slice(0, MAX_ROWS)
894
1185
  };
@@ -915,7 +1206,7 @@ var azureSqlConnector = new ConnectorPlugin({
915
1206
  systemPrompt: {
916
1207
  en: `### Tools
917
1208
 
918
- - \`azure-sql_executeQuery\`: Executes a T-SQL query against Azure SQL Database and returns rows. Use for schema exploration via \`INFORMATION_SCHEMA\` and data sampling. See the SQL Reference below for Azure SQL-specific notes.
1209
+ - \`connector_azure-sql_executeQuery\`: Executes a T-SQL query against Azure SQL Database and returns rows. Use for schema exploration via \`INFORMATION_SCHEMA\` and data sampling. See the SQL Reference below for Azure SQL-specific notes.
919
1210
 
920
1211
  ### Business Logic
921
1212
 
@@ -932,7 +1223,7 @@ The business logic type for this connector is "sql".
932
1223
  - Row-limit compatibility: the platform's server-logic schema inference may wrap your query as \`SELECT * FROM (<inner>) AS _sq LIMIT N\`. T-SQL does not understand \`LIMIT\`, so the connector detects this exact wrapper at \`query()\` time, executes \`<inner>\` directly, and slices the first N rows in JS. You do not need to handle this \u2014 but do not author your own \`LIMIT\` clauses; use \`TOP\` / \`OFFSET ... FETCH NEXT\` in queries you write.`,
933
1224
  ja: `### \u30C4\u30FC\u30EB
934
1225
 
935
- - \`azure-sql_executeQuery\`: Azure SQL Database \u306B\u5BFE\u3057\u3066 T-SQL \u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u3057\u3001\u884C\u30C7\u30FC\u30BF\u3092\u8FD4\u3057\u307E\u3059\u3002\`INFORMATION_SCHEMA\` \u3092\u4F7F\u3063\u305F\u30B9\u30AD\u30FC\u30DE\u63A2\u7D22\u3084\u30C7\u30FC\u30BF\u306E\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u306B\u4F7F\u3044\u307E\u3059\u3002Azure SQL \u56FA\u6709\u306E\u6CE8\u610F\u70B9\u306F\u4E0B\u90E8\u306E\u300CSQL \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9\u300D\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002
1226
+ - \`connector_azure-sql_executeQuery\`: Azure SQL Database \u306B\u5BFE\u3057\u3066 T-SQL \u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u3057\u3001\u884C\u30C7\u30FC\u30BF\u3092\u8FD4\u3057\u307E\u3059\u3002\`INFORMATION_SCHEMA\` \u3092\u4F7F\u3063\u305F\u30B9\u30AD\u30FC\u30DE\u63A2\u7D22\u3084\u30C7\u30FC\u30BF\u306E\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u306B\u4F7F\u3044\u307E\u3059\u3002Azure SQL \u56FA\u6709\u306E\u6CE8\u610F\u70B9\u306F\u4E0B\u90E8\u306E\u300CSQL \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9\u300D\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002
936
1227
 
937
1228
  ### Business Logic
938
1229
 
@@ -949,6 +1240,12 @@ The business logic type for this connector is "sql".
949
1240
  - \u884C\u6570\u5236\u9650\u306E\u4E92\u63DB\u6027: \u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0\u306E server-logic \u30B9\u30AD\u30FC\u30DE\u63A8\u8AD6\u306F\u3001\u30AF\u30A8\u30EA\u3092 \`SELECT * FROM (<inner>) AS _sq LIMIT N\` \u306E\u5F62\u3067\u30E9\u30C3\u30D7\u3057\u3066\u304F\u308B\u3053\u3068\u304C\u3042\u308A\u307E\u3059\u3002T-SQL \u306B\u306F \`LIMIT\` \u304C\u7121\u3044\u305F\u3081\u3001\u30B3\u30CD\u30AF\u30BF\u306F \`query()\` \u5185\u3067\u3053\u306E\u30E9\u30C3\u30D1\u3092\u691C\u51FA\u3057\u3001\`<inner>\` \u3092\u305D\u306E\u307E\u307E\u5B9F\u884C\u3057\u3066 JS \u5074\u3067\u5148\u982D N \u884C\u306B\u5207\u308A\u8A70\u3081\u307E\u3059\u3002\u5229\u7528\u8005\u5074\u3067\u5BFE\u51E6\u3059\u308B\u5FC5\u8981\u306F\u3042\u308A\u307E\u305B\u3093\u304C\u3001\u81EA\u5206\u3067\u66F8\u304F SQL \u3067\u306F \`LIMIT\` \u3092\u4F7F\u308F\u305A \`TOP\` / \`OFFSET ... FETCH NEXT\` \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044\u3002`
950
1241
  },
951
1242
  tools,
1243
+ // 決定論的な立ち上げ survey(ルールベース prewarm)。Azure SQL はユーザーオブジェクトが既定 `dbo`、識別子は `[ ]`。
1244
+ surveyProbes: makeStandardSqlSurveyProbes({
1245
+ schemaLiteral: "dbo",
1246
+ bracket: true
1247
+ }),
1248
+ introspect: (ctx) => withRowCounts(ctx, introspectMssql(ctx.query), quoteBracket),
952
1249
  setup: (params, ctx, config) => runSetupFlow(azureSqlSetupFlow, params, ctx, config),
953
1250
  async checkConnection(params, _config) {
954
1251
  return checkMssqlConnection(