@kepler.gl/mcp 0.0.0-stage → 3.3.0-alpha.19

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 (73) hide show
  1. package/dist/cjs/commands/add-column-command.js +192 -0
  2. package/dist/cjs/commands/basemap-command.js +80 -0
  3. package/dist/cjs/commands/boundary-command.js +81 -0
  4. package/dist/cjs/commands/command-wrappers.js +122 -0
  5. package/dist/cjs/commands/dataset-context-command.js +87 -0
  6. package/dist/cjs/commands/index.js +230 -0
  7. package/dist/cjs/commands/layer-creation-command.js +534 -0
  8. package/dist/cjs/commands/layer-style-command.js +136 -0
  9. package/dist/cjs/commands/load-data-command.js +270 -0
  10. package/dist/cjs/commands/save-data-command.js +118 -0
  11. package/dist/cjs/commands/split-view-command.js +261 -0
  12. package/dist/cjs/commands/table-command.js +199 -0
  13. package/dist/cjs/commands/time-filter-command.js +289 -0
  14. package/dist/cjs/commands/toggle-time-filter-command.js +155 -0
  15. package/dist/cjs/commands/types.js +6 -0
  16. package/dist/cjs/commands/utils.js +536 -0
  17. package/dist/cjs/commands/view-mode-command.js +94 -0
  18. package/dist/cjs/index.js +39 -0
  19. package/dist/cjs/map-contract.js +6 -0
  20. package/dist/cjs/server/bridge-server.js +435 -0
  21. package/dist/cjs/server/index.js +31 -0
  22. package/dist/cjs/server/stdio.js +201 -0
  23. package/dist/cjs/types.js +30 -0
  24. package/dist/commands/add-column-command.d.ts +4 -0
  25. package/dist/commands/basemap-command.d.ts +4 -0
  26. package/dist/commands/boundary-command.d.ts +4 -0
  27. package/dist/commands/command-wrappers.d.ts +52 -0
  28. package/dist/commands/dataset-context-command.d.ts +4 -0
  29. package/dist/commands/index.d.ts +31 -0
  30. package/dist/commands/layer-creation-command.d.ts +8 -0
  31. package/dist/commands/layer-style-command.d.ts +4 -0
  32. package/dist/commands/load-data-command.d.ts +4 -0
  33. package/dist/commands/save-data-command.d.ts +4 -0
  34. package/dist/commands/split-view-command.d.ts +4 -0
  35. package/dist/commands/table-command.d.ts +4 -0
  36. package/dist/commands/time-filter-command.d.ts +13 -0
  37. package/dist/commands/toggle-time-filter-command.d.ts +4 -0
  38. package/dist/commands/types.d.ts +132 -0
  39. package/dist/commands/utils.d.ts +138 -0
  40. package/dist/commands/view-mode-command.d.ts +4 -0
  41. package/dist/esm/commands/add-column-command.js +185 -0
  42. package/dist/esm/commands/basemap-command.js +72 -0
  43. package/dist/esm/commands/boundary-command.js +73 -0
  44. package/dist/esm/commands/command-wrappers.js +114 -0
  45. package/dist/esm/commands/dataset-context-command.js +79 -0
  46. package/dist/esm/commands/index.js +51 -0
  47. package/dist/esm/commands/layer-creation-command.js +527 -0
  48. package/dist/esm/commands/layer-style-command.js +130 -0
  49. package/dist/esm/commands/load-data-command.js +264 -0
  50. package/dist/esm/commands/save-data-command.js +112 -0
  51. package/dist/esm/commands/split-view-command.js +255 -0
  52. package/dist/esm/commands/table-command.js +194 -0
  53. package/dist/esm/commands/time-filter-command.js +280 -0
  54. package/dist/esm/commands/toggle-time-filter-command.js +147 -0
  55. package/dist/esm/commands/types.js +3 -0
  56. package/dist/esm/commands/utils.js +521 -0
  57. package/dist/esm/commands/view-mode-command.js +86 -0
  58. package/dist/esm/index.js +20 -0
  59. package/dist/esm/map-contract.js +3 -0
  60. package/dist/esm/server/bridge-server.js +428 -0
  61. package/dist/esm/server/index.js +13 -0
  62. package/dist/esm/server/stdio.js +198 -0
  63. package/dist/esm/types.js +24 -0
  64. package/dist/index.d.ts +15 -0
  65. package/dist/map-contract.d.ts +31 -0
  66. package/dist/server/bridge-server.d.ts +53 -0
  67. package/dist/server/index.d.ts +9 -0
  68. package/dist/server/stdio.d.ts +2 -0
  69. package/dist/types.d.ts +24 -0
  70. package/package.json +84 -4
  71. package/skill/kepler/SKILL.md +438 -0
  72. package/skill/kepler/skill.yaml +4 -0
  73. package/README.md +0 -3
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env node
2
+
3
+ // SPDX-License-Identifier: MIT
4
+ // Copyright contributors to the kepler.gl project
5
+
6
+ /**
7
+ * `kepler-mcp` — a stdio MCP server for the kepler.gl map surface.
8
+ *
9
+ * The agent starts this process (it speaks MCP on stdin/stdout); the process
10
+ * also listens for the map page on a loopback WebSocket. It prints a URL that
11
+ * carries the one-time token — open that URL and the page connects, after which
12
+ * every map.* tool call executes against the live map.
13
+ *
14
+ * stdout belongs to the MCP protocol: every log line here goes to stderr.
15
+ */
16
+ "use strict";
17
+
18
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
19
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
20
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
21
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
22
+ var _nodeFs = require("node:fs");
23
+ var _nodePath = require("node:path");
24
+ var _index = require("@modelcontextprotocol/sdk/server/index.js");
25
+ var _stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
26
+ var _types = require("@modelcontextprotocol/sdk/types.js");
27
+ var _bridgeServer = require("./bridge-server");
28
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
29
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
30
+ var DEFAULT_MAP_URL = 'http://localhost:8080';
31
+ function readVersion() {
32
+ if (typeof __dirname === 'undefined') return '0.0.0';
33
+ var directory = __dirname;
34
+ // Walk up until the package manifest is found, so this works both from src/
35
+ // (babel-node, tests) and from dist/cjs/server (the published bin).
36
+ for (var depth = 0; depth < 5; depth++) {
37
+ try {
38
+ var manifest = JSON.parse((0, _nodeFs.readFileSync)((0, _nodePath.join)(directory, 'package.json'), 'utf8'));
39
+ if (manifest.name === '@kepler.gl/mcp') return manifest.version;
40
+ } catch (_unused) {
41
+ // no manifest at this level — keep walking
42
+ }
43
+ directory = (0, _nodePath.dirname)(directory);
44
+ }
45
+ return '0.0.0';
46
+ }
47
+ function usage() {
48
+ return ['Usage: kepler-mcp [--port <n>] [--host <h>] [--map-url <url>]', '', 'Runs a stdio MCP server for the kepler.gl map surface and waits for a', 'kepler.gl page to connect over a loopback WebSocket.', '', ' --port <n> WebSocket port for the page (default 8765)', ' --host <h> loopback host to bind (default 127.0.0.1)', " --map-url <url> page URL printed with the token (default ".concat(DEFAULT_MAP_URL, ")")].join('\n');
49
+ }
50
+ function parseArgs(argv) {
51
+ var options = {};
52
+ for (var i = 0; i < argv.length; i++) {
53
+ var arg = argv[i];
54
+ if (arg === '--help' || arg === '-h') {
55
+ options.help = true;
56
+ } else if (arg === '--port') {
57
+ var value = Number(argv[++i]);
58
+ if (!Number.isInteger(value) || value < 0 || value > 65535) {
59
+ throw new Error("Invalid --port value: ".concat(argv[i]));
60
+ }
61
+ options.port = value;
62
+ } else if (arg === '--host') {
63
+ options.host = argv[++i];
64
+ } else if (arg === '--map-url') {
65
+ options.mapUrl = argv[++i];
66
+ } else {
67
+ throw new Error("Unknown argument: ".concat(arg));
68
+ }
69
+ }
70
+ return options;
71
+ }
72
+ function main() {
73
+ return _main.apply(this, arguments);
74
+ }
75
+ function _main() {
76
+ _main = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee4() {
77
+ var options, bridge, started, server, shutdown;
78
+ return _regenerator["default"].wrap(function _callee4$(_context4) {
79
+ while (1) switch (_context4.prev = _context4.next) {
80
+ case 0:
81
+ options = parseArgs(process.argv.slice(2));
82
+ if (!options.help) {
83
+ _context4.next = 4;
84
+ break;
85
+ }
86
+ console.error(usage());
87
+ return _context4.abrupt("return");
88
+ case 4:
89
+ bridge = new _bridgeServer.KeplerMcpBridge(options);
90
+ _context4.next = 7;
91
+ return bridge.start();
92
+ case 7:
93
+ started = _context4.sent;
94
+ server = new _index.Server({
95
+ name: 'kepler-mcp',
96
+ version: readVersion()
97
+ }, {
98
+ capabilities: {
99
+ tools: {}
100
+ }
101
+ });
102
+ server.setRequestHandler(_types.ListToolsRequestSchema, /*#__PURE__*/(0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee() {
103
+ return _regenerator["default"].wrap(function _callee$(_context) {
104
+ while (1) switch (_context.prev = _context.next) {
105
+ case 0:
106
+ return _context.abrupt("return", {
107
+ tools: bridge.getTools().map(function (tool) {
108
+ return {
109
+ name: tool.name,
110
+ description: tool.description,
111
+ inputSchema: tool.inputSchema
112
+ };
113
+ })
114
+ });
115
+ case 1:
116
+ case "end":
117
+ return _context.stop();
118
+ }
119
+ }, _callee);
120
+ })));
121
+ server.setRequestHandler(_types.CallToolRequestSchema, /*#__PURE__*/function () {
122
+ var _ref2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee2(request) {
123
+ var _request$params, name, args, result, _formatResult, text, isError;
124
+ return _regenerator["default"].wrap(function _callee2$(_context2) {
125
+ while (1) switch (_context2.prev = _context2.next) {
126
+ case 0:
127
+ _request$params = request.params, name = _request$params.name, args = _request$params.arguments;
128
+ _context2.prev = 1;
129
+ _context2.next = 4;
130
+ return bridge.callTool(name, args !== null && args !== void 0 ? args : {});
131
+ case 4:
132
+ result = _context2.sent;
133
+ _formatResult = (0, _bridgeServer.formatResult)(result), text = _formatResult.text, isError = _formatResult.isError;
134
+ return _context2.abrupt("return", _objectSpread({
135
+ content: [{
136
+ type: 'text',
137
+ text: text
138
+ }]
139
+ }, isError ? {
140
+ isError: true
141
+ } : {}));
142
+ case 9:
143
+ _context2.prev = 9;
144
+ _context2.t0 = _context2["catch"](1);
145
+ return _context2.abrupt("return", {
146
+ content: [{
147
+ type: 'text',
148
+ text: _context2.t0 instanceof Error ? _context2.t0.message : String(_context2.t0)
149
+ }],
150
+ isError: true
151
+ });
152
+ case 12:
153
+ case "end":
154
+ return _context2.stop();
155
+ }
156
+ }, _callee2, null, [[1, 9]]);
157
+ }));
158
+ return function (_x) {
159
+ return _ref2.apply(this, arguments);
160
+ };
161
+ }());
162
+ shutdown = /*#__PURE__*/function () {
163
+ var _ref3 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee3() {
164
+ return _regenerator["default"].wrap(function _callee3$(_context3) {
165
+ while (1) switch (_context3.prev = _context3.next) {
166
+ case 0:
167
+ _context3.next = 2;
168
+ return bridge.close();
169
+ case 2:
170
+ process.exit(0);
171
+ case 3:
172
+ case "end":
173
+ return _context3.stop();
174
+ }
175
+ }, _callee3);
176
+ }));
177
+ return function shutdown() {
178
+ return _ref3.apply(this, arguments);
179
+ };
180
+ }();
181
+ process.on('SIGINT', shutdown);
182
+ process.on('SIGTERM', shutdown);
183
+ _context4.next = 16;
184
+ return server.connect(new _stdio.StdioServerTransport());
185
+ case 16:
186
+ console.error("[kepler-mcp] bridge listening on ws://".concat(started.host, ":").concat(started.port, "/ws"));
187
+ console.error("[kepler-mcp] open http://".concat(started.host, ":").concat(started.port, "/ in a browser \u2014 it redirects ") + 'to the map page with the token — so the agent can drive the map');
188
+ console.error("[kepler-mcp] or open ".concat(started.pageUrl));
189
+ case 19:
190
+ case "end":
191
+ return _context4.stop();
192
+ }
193
+ }, _callee4);
194
+ }));
195
+ return _main.apply(this, arguments);
196
+ }
197
+ main()["catch"](function (error) {
198
+ console.error("[kepler-mcp] ".concat(error instanceof Error ? error.message : String(error)));
199
+ process.exit(1);
200
+ });
201
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9yZWdlbmVyYXRvciIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJfYXN5bmNUb0dlbmVyYXRvcjIiLCJfbm9kZUZzIiwiX25vZGVQYXRoIiwiX2luZGV4IiwiX3N0ZGlvIiwiX3R5cGVzIiwiX2JyaWRnZVNlcnZlciIsIm93bktleXMiLCJlIiwiciIsInQiLCJPYmplY3QiLCJrZXlzIiwiZ2V0T3duUHJvcGVydHlTeW1ib2xzIiwibyIsImZpbHRlciIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsImVudW1lcmFibGUiLCJwdXNoIiwiYXBwbHkiLCJfb2JqZWN0U3ByZWFkIiwiYXJndW1lbnRzIiwibGVuZ3RoIiwiZm9yRWFjaCIsImdldE93blByb3BlcnR5RGVzY3JpcHRvcnMiLCJkZWZpbmVQcm9wZXJ0aWVzIiwiZGVmaW5lUHJvcGVydHkiLCJERUZBVUxUX01BUF9VUkwiLCJyZWFkVmVyc2lvbiIsIl9fZGlybmFtZSIsImRpcmVjdG9yeSIsImRlcHRoIiwibWFuaWZlc3QiLCJKU09OIiwicGFyc2UiLCJyZWFkRmlsZVN5bmMiLCJqb2luIiwibmFtZSIsInZlcnNpb24iLCJfdW51c2VkIiwiZGlybmFtZSIsInVzYWdlIiwiY29uY2F0IiwicGFyc2VBcmdzIiwiYXJndiIsIm9wdGlvbnMiLCJpIiwiYXJnIiwiaGVscCIsInZhbHVlIiwiTnVtYmVyIiwiaXNJbnRlZ2VyIiwiRXJyb3IiLCJwb3J0IiwiaG9zdCIsIm1hcFVybCIsIm1haW4iLCJfbWFpbiIsIm1hcmsiLCJfY2FsbGVlNCIsImJyaWRnZSIsInN0YXJ0ZWQiLCJzZXJ2ZXIiLCJzaHV0ZG93biIsIndyYXAiLCJfY2FsbGVlNCQiLCJfY29udGV4dDQiLCJwcmV2IiwibmV4dCIsInByb2Nlc3MiLCJzbGljZSIsImNvbnNvbGUiLCJlcnJvciIsImFicnVwdCIsIktlcGxlck1jcEJyaWRnZSIsInN0YXJ0Iiwic2VudCIsIlNlcnZlciIsImNhcGFiaWxpdGllcyIsInRvb2xzIiwic2V0UmVxdWVzdEhhbmRsZXIiLCJMaXN0VG9vbHNSZXF1ZXN0U2NoZW1hIiwiX2NhbGxlZSIsIl9jYWxsZWUkIiwiX2NvbnRleHQiLCJnZXRUb29scyIsIm1hcCIsInRvb2wiLCJkZXNjcmlwdGlvbiIsImlucHV0U2NoZW1hIiwic3RvcCIsIkNhbGxUb29sUmVxdWVzdFNjaGVtYSIsIl9yZWYyIiwiX2NhbGxlZTIiLCJyZXF1ZXN0IiwiX3JlcXVlc3QkcGFyYW1zIiwiYXJncyIsInJlc3VsdCIsIl9mb3JtYXRSZXN1bHQiLCJ0ZXh0IiwiaXNFcnJvciIsIl9jYWxsZWUyJCIsIl9jb250ZXh0MiIsInBhcmFtcyIsImNhbGxUb29sIiwiZm9ybWF0UmVzdWx0IiwiY29udGVudCIsInR5cGUiLCJ0MCIsIm1lc3NhZ2UiLCJTdHJpbmciLCJfeCIsIl9yZWYzIiwiX2NhbGxlZTMiLCJfY2FsbGVlMyQiLCJfY29udGV4dDMiLCJjbG9zZSIsImV4aXQiLCJvbiIsImNvbm5lY3QiLCJTdGRpb1NlcnZlclRyYW5zcG9ydCIsInBhZ2VVcmwiXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmVyL3N0ZGlvLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIiMhL3Vzci9iaW4vZW52IG5vZGVcblxuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVFxuLy8gQ29weXJpZ2h0IGNvbnRyaWJ1dG9ycyB0byB0aGUga2VwbGVyLmdsIHByb2plY3RcblxuLyoqXG4gKiBga2VwbGVyLW1jcGAg4oCUIGEgc3RkaW8gTUNQIHNlcnZlciBmb3IgdGhlIGtlcGxlci5nbCBtYXAgc3VyZmFjZS5cbiAqXG4gKiBUaGUgYWdlbnQgc3RhcnRzIHRoaXMgcHJvY2VzcyAoaXQgc3BlYWtzIE1DUCBvbiBzdGRpbi9zdGRvdXQpOyB0aGUgcHJvY2Vzc1xuICogYWxzbyBsaXN0ZW5zIGZvciB0aGUgbWFwIHBhZ2Ugb24gYSBsb29wYmFjayBXZWJTb2NrZXQuIEl0IHByaW50cyBhIFVSTCB0aGF0XG4gKiBjYXJyaWVzIHRoZSBvbmUtdGltZSB0b2tlbiDigJQgb3BlbiB0aGF0IFVSTCBhbmQgdGhlIHBhZ2UgY29ubmVjdHMsIGFmdGVyIHdoaWNoXG4gKiBldmVyeSBtYXAuKiB0b29sIGNhbGwgZXhlY3V0ZXMgYWdhaW5zdCB0aGUgbGl2ZSBtYXAuXG4gKlxuICogc3Rkb3V0IGJlbG9uZ3MgdG8gdGhlIE1DUCBwcm90b2NvbDogZXZlcnkgbG9nIGxpbmUgaGVyZSBnb2VzIHRvIHN0ZGVyci5cbiAqL1xuXG5pbXBvcnQge3JlYWRGaWxlU3luY30gZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQge2Rpcm5hbWUsIGpvaW59IGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQge1NlcnZlcn0gZnJvbSAnQG1vZGVsY29udGV4dHByb3RvY29sL3Nkay9zZXJ2ZXIvaW5kZXguanMnO1xuaW1wb3J0IHtTdGRpb1NlcnZlclRyYW5zcG9ydH0gZnJvbSAnQG1vZGVsY29udGV4dHByb3RvY29sL3Nkay9zZXJ2ZXIvc3RkaW8uanMnO1xuaW1wb3J0IHtDYWxsVG9vbFJlcXVlc3RTY2hlbWEsIExpc3RUb29sc1JlcXVlc3RTY2hlbWF9IGZyb20gJ0Btb2RlbGNvbnRleHRwcm90b2NvbC9zZGsvdHlwZXMuanMnO1xuaW1wb3J0IHtLZXBsZXJNY3BCcmlkZ2UsIGZvcm1hdFJlc3VsdH0gZnJvbSAnLi9icmlkZ2Utc2VydmVyJztcbmltcG9ydCB0eXBlIHtLZXBsZXJNY3BCcmlkZ2VPcHRpb25zfSBmcm9tICcuL2JyaWRnZS1zZXJ2ZXInO1xuXG5jb25zdCBERUZBVUxUX01BUF9VUkwgPSAnaHR0cDovL2xvY2FsaG9zdDo4MDgwJztcblxuZnVuY3Rpb24gcmVhZFZlcnNpb24oKTogc3RyaW5nIHtcbiAgaWYgKHR5cGVvZiBfX2Rpcm5hbWUgPT09ICd1bmRlZmluZWQnKSByZXR1cm4gJzAuMC4wJztcbiAgbGV0IGRpcmVjdG9yeSA9IF9fZGlybmFtZTtcbiAgLy8gV2FsayB1cCB1bnRpbCB0aGUgcGFja2FnZSBtYW5pZmVzdCBpcyBmb3VuZCwgc28gdGhpcyB3b3JrcyBib3RoIGZyb20gc3JjL1xuICAvLyAoYmFiZWwtbm9kZSwgdGVzdHMpIGFuZCBmcm9tIGRpc3QvY2pzL3NlcnZlciAodGhlIHB1Ymxpc2hlZCBiaW4pLlxuICBmb3IgKGxldCBkZXB0aCA9IDA7IGRlcHRoIDwgNTsgZGVwdGgrKykge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGpvaW4oZGlyZWN0b3J5LCAncGFja2FnZS5qc29uJyksICd1dGY4JykpO1xuICAgICAgaWYgKG1hbmlmZXN0Lm5hbWUgPT09ICdAa2VwbGVyLmdsL21jcCcpIHJldHVybiBtYW5pZmVzdC52ZXJzaW9uO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gbm8gbWFuaWZlc3QgYXQgdGhpcyBsZXZlbCDigJQga2VlcCB3YWxraW5nXG4gICAgfVxuICAgIGRpcmVjdG9yeSA9IGRpcm5hbWUoZGlyZWN0b3J5KTtcbiAgfVxuICByZXR1cm4gJzAuMC4wJztcbn1cblxuZnVuY3Rpb24gdXNhZ2UoKTogc3RyaW5nIHtcbiAgcmV0dXJuIFtcbiAgICAnVXNhZ2U6IGtlcGxlci1tY3AgWy0tcG9ydCA8bj5dIFstLWhvc3QgPGg+XSBbLS1tYXAtdXJsIDx1cmw+XScsXG4gICAgJycsXG4gICAgJ1J1bnMgYSBzdGRpbyBNQ1Agc2VydmVyIGZvciB0aGUga2VwbGVyLmdsIG1hcCBzdXJmYWNlIGFuZCB3YWl0cyBmb3IgYScsXG4gICAgJ2tlcGxlci5nbCBwYWdlIHRvIGNvbm5lY3Qgb3ZlciBhIGxvb3BiYWNrIFdlYlNvY2tldC4nLFxuICAgICcnLFxuICAgICcgIC0tcG9ydCA8bj4gICAgICAgV2ViU29ja2V0IHBvcnQgZm9yIHRoZSBwYWdlIChkZWZhdWx0IDg3NjUpJyxcbiAgICAnICAtLWhvc3QgPGg+ICAgICAgIGxvb3BiYWNrIGhvc3QgdG8gYmluZCAoZGVmYXVsdCAxMjcuMC4wLjEpJyxcbiAgICBgICAtLW1hcC11cmwgPHVybD4gIHBhZ2UgVVJMIHByaW50ZWQgd2l0aCB0aGUgdG9rZW4gKGRlZmF1bHQgJHtERUZBVUxUX01BUF9VUkx9KWBcbiAgXS5qb2luKCdcXG4nKTtcbn1cblxuZnVuY3Rpb24gcGFyc2VBcmdzKGFyZ3Y6IHN0cmluZ1tdKTogS2VwbGVyTWNwQnJpZGdlT3B0aW9ucyAmIHtoZWxwPzogYm9vbGVhbn0ge1xuICBjb25zdCBvcHRpb25zOiBLZXBsZXJNY3BCcmlkZ2VPcHRpb25zICYge2hlbHA/OiBib29sZWFufSA9IHt9O1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3YubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBhcmcgPSBhcmd2W2ldO1xuICAgIGlmIChhcmcgPT09ICctLWhlbHAnIHx8IGFyZyA9PT0gJy1oJykge1xuICAgICAgb3B0aW9ucy5oZWxwID0gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKGFyZyA9PT0gJy0tcG9ydCcpIHtcbiAgICAgIGNvbnN0IHZhbHVlID0gTnVtYmVyKGFyZ3ZbKytpXSk7XG4gICAgICBpZiAoIU51bWJlci5pc0ludGVnZXIodmFsdWUpIHx8IHZhbHVlIDwgMCB8fCB2YWx1ZSA+IDY1NTM1KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCAtLXBvcnQgdmFsdWU6ICR7YXJndltpXX1gKTtcbiAgICAgIH1cbiAgICAgIG9wdGlvbnMucG9ydCA9IHZhbHVlO1xuICAgIH0gZWxzZSBpZiAoYXJnID09PSAnLS1ob3N0Jykge1xuICAgICAgb3B0aW9ucy5ob3N0ID0gYXJndlsrK2ldO1xuICAgIH0gZWxzZSBpZiAoYXJnID09PSAnLS1tYXAtdXJsJykge1xuICAgICAgb3B0aW9ucy5tYXBVcmwgPSBhcmd2WysraV07XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBhcmd1bWVudDogJHthcmd9YCk7XG4gICAgfVxuICB9XG4gIHJldHVybiBvcHRpb25zO1xufVxuXG5hc3luYyBmdW5jdGlvbiBtYWluKCk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBvcHRpb25zID0gcGFyc2VBcmdzKHByb2Nlc3MuYXJndi5zbGljZSgyKSk7XG4gIGlmIChvcHRpb25zLmhlbHApIHtcbiAgICBjb25zb2xlLmVycm9yKHVzYWdlKCkpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGJyaWRnZSA9IG5ldyBLZXBsZXJNY3BCcmlkZ2Uob3B0aW9ucyk7XG4gIGNvbnN0IHN0YXJ0ZWQgPSBhd2FpdCBicmlkZ2Uuc3RhcnQoKTtcblxuICBjb25zdCBzZXJ2ZXIgPSBuZXcgU2VydmVyKFxuICAgIHtuYW1lOiAna2VwbGVyLW1jcCcsIHZlcnNpb246IHJlYWRWZXJzaW9uKCl9LFxuICAgIHtjYXBhYmlsaXRpZXM6IHt0b29sczoge319fVxuICApO1xuXG4gIHNlcnZlci5zZXRSZXF1ZXN0SGFuZGxlcihMaXN0VG9vbHNSZXF1ZXN0U2NoZW1hLCBhc3luYyAoKSA9PiAoe1xuICAgIHRvb2xzOiBicmlkZ2UuZ2V0VG9vbHMoKS5tYXAodG9vbCA9PiAoe1xuICAgICAgbmFtZTogdG9vbC5uYW1lLFxuICAgICAgZGVzY3JpcHRpb246IHRvb2wuZGVzY3JpcHRpb24sXG4gICAgICBpbnB1dFNjaGVtYTogdG9vbC5pbnB1dFNjaGVtYSBhcyB7dHlwZTogJ29iamVjdCc7IFtrZXk6IHN0cmluZ106IHVua25vd259XG4gICAgfSkpXG4gIH0pKTtcblxuICBzZXJ2ZXIuc2V0UmVxdWVzdEhhbmRsZXIoQ2FsbFRvb2xSZXF1ZXN0U2NoZW1hLCBhc3luYyByZXF1ZXN0ID0+IHtcbiAgICBjb25zdCB7bmFtZSwgYXJndW1lbnRzOiBhcmdzfSA9IHJlcXVlc3QucGFyYW1zO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBicmlkZ2UuY2FsbFRvb2wobmFtZSwgKGFyZ3MgPz8ge30pIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KTtcbiAgICAgIGNvbnN0IHt0ZXh0LCBpc0Vycm9yfSA9IGZvcm1hdFJlc3VsdChyZXN1bHQpO1xuICAgICAgcmV0dXJuIHtjb250ZW50OiBbe3R5cGU6ICd0ZXh0JyBhcyBjb25zdCwgdGV4dH1dLCAuLi4oaXNFcnJvciA/IHtpc0Vycm9yOiB0cnVlfSA6IHt9KX07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbnRlbnQ6IFtcbiAgICAgICAgICB7dHlwZTogJ3RleHQnIGFzIGNvbnN0LCB0ZXh0OiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9XG4gICAgICAgIF0sXG4gICAgICAgIGlzRXJyb3I6IHRydWVcbiAgICAgIH07XG4gICAgfVxuICB9KTtcblxuICBjb25zdCBzaHV0ZG93biA9IGFzeW5jICgpID0+IHtcbiAgICBhd2FpdCBicmlkZ2UuY2xvc2UoKTtcbiAgICBwcm9jZXNzLmV4aXQoMCk7XG4gIH07XG4gIHByb2Nlc3Mub24oJ1NJR0lOVCcsIHNodXRkb3duKTtcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIHNodXRkb3duKTtcblxuICBhd2FpdCBzZXJ2ZXIuY29ubmVjdChuZXcgU3RkaW9TZXJ2ZXJUcmFuc3BvcnQoKSk7XG5cbiAgY29uc29sZS5lcnJvcihgW2tlcGxlci1tY3BdIGJyaWRnZSBsaXN0ZW5pbmcgb24gd3M6Ly8ke3N0YXJ0ZWQuaG9zdH06JHtzdGFydGVkLnBvcnR9L3dzYCk7XG4gIGNvbnNvbGUuZXJyb3IoXG4gICAgYFtrZXBsZXItbWNwXSBvcGVuIGh0dHA6Ly8ke3N0YXJ0ZWQuaG9zdH06JHtzdGFydGVkLnBvcnR9LyBpbiBhIGJyb3dzZXIg4oCUIGl0IHJlZGlyZWN0cyBgICtcbiAgICAgICd0byB0aGUgbWFwIHBhZ2Ugd2l0aCB0aGUgdG9rZW4g4oCUIHNvIHRoZSBhZ2VudCBjYW4gZHJpdmUgdGhlIG1hcCdcbiAgKTtcbiAgY29uc29sZS5lcnJvcihgW2tlcGxlci1tY3BdIG9yIG9wZW4gJHtzdGFydGVkLnBhZ2VVcmx9YCk7XG59XG5cbm1haW4oKS5jYXRjaChlcnJvciA9PiB7XG4gIGNvbnNvbGUuZXJyb3IoYFtrZXBsZXItbWNwXSAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gKTtcbiAgcHJvY2Vzcy5leGl0KDEpO1xufSk7XG4iXSwibWFwcGluZ3MiOiJBQUFBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFUQTs7QUFBQSxJQUFBQSxzQkFBQSxHQUFBQyxPQUFBO0FBQUEsSUFBQUMsWUFBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FBQUEsSUFBQUUsZ0JBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTtBQUFBLElBQUFHLGtCQUFBLEdBQUFKLHNCQUFBLENBQUFDLE9BQUE7QUFXQSxJQUFBSSxPQUFBLEdBQUFKLE9BQUE7QUFDQSxJQUFBSyxTQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxNQUFBLEdBQUFOLE9BQUE7QUFDQSxJQUFBTyxNQUFBLEdBQUFQLE9BQUE7QUFDQSxJQUFBUSxNQUFBLEdBQUFSLE9BQUE7QUFDQSxJQUFBUyxhQUFBLEdBQUFULE9BQUE7QUFBOEQsU0FBQVUsUUFBQUMsQ0FBQSxFQUFBQyxDQUFBLFFBQUFDLENBQUEsR0FBQUMsTUFBQSxDQUFBQyxJQUFBLENBQUFKLENBQUEsT0FBQUcsTUFBQSxDQUFBRSxxQkFBQSxRQUFBQyxDQUFBLEdBQUFILE1BQUEsQ0FBQUUscUJBQUEsQ0FBQUwsQ0FBQSxHQUFBQyxDQUFBLEtBQUFLLENBQUEsR0FBQUEsQ0FBQSxDQUFBQyxNQUFBLFdBQUFOLENBQUEsV0FBQUUsTUFBQSxDQUFBSyx3QkFBQSxDQUFBUixDQUFBLEVBQUFDLENBQUEsRUFBQVEsVUFBQSxPQUFBUCxDQUFBLENBQUFRLElBQUEsQ0FBQUMsS0FBQSxDQUFBVCxDQUFBLEVBQUFJLENBQUEsWUFBQUosQ0FBQTtBQUFBLFNBQUFVLGNBQUFaLENBQUEsYUFBQUMsQ0FBQSxNQUFBQSxDQUFBLEdBQUFZLFNBQUEsQ0FBQUMs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
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.MAP_TOOL_IDS = void 0;
7
+ // SPDX-License-Identifier: MIT
8
+ // Copyright contributors to the kepler.gl project
9
+
10
+ /**
11
+ * Shared contract types for the kepler.gl map surface.
12
+ *
13
+ * This module is the home of the reusable *map surface* contract — the map.*
14
+ * tool namespace that any AI client can drive. It defines the map.* tool ids
15
+ * and the `ToolResult` shape so any host (the demo-app browser page, the
16
+ * kepler-assistant library, or a future MCP server) can implement or consume
17
+ * the same contract.
18
+ */
19
+
20
+ /** A command/tool execution result. */
21
+
22
+ /**
23
+ * The v1 map tool surface. These are the command ids the kepler.gl demo-app's
24
+ * assistant actually registers, reconciled with the kepler-mcp proposal. Most
25
+ * commands are pure map actuation (set-basemap, add-layer, ...); the table ops
26
+ * (map.create-table, map.add-column, map.save-data) are DuckDB-backed and are
27
+ * included because they mutate the map's datasets in place.
28
+ */
29
+ var MAP_TOOL_IDS = exports.MAP_TOOL_IDS = ['map.set-basemap', 'map.get-boundary', 'map.add-layer', 'map.update-layer-color', 'map.load-data', 'map.save-data', 'map.create-table', 'map.add-column', 'map.add-time-filter', 'map.toggle-time-filter', 'map.split-view', 'map.get-dataset-context'];
30
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNQVBfVE9PTF9JRFMiLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3R5cGVzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVRcbi8vIENvcHlyaWdodCBjb250cmlidXRvcnMgdG8gdGhlIGtlcGxlci5nbCBwcm9qZWN0XG5cbi8qKlxuICogU2hhcmVkIGNvbnRyYWN0IHR5cGVzIGZvciB0aGUga2VwbGVyLmdsIG1hcCBzdXJmYWNlLlxuICpcbiAqIFRoaXMgbW9kdWxlIGlzIHRoZSBob21lIG9mIHRoZSByZXVzYWJsZSAqbWFwIHN1cmZhY2UqIGNvbnRyYWN0IOKAlCB0aGUgbWFwLipcbiAqIHRvb2wgbmFtZXNwYWNlIHRoYXQgYW55IEFJIGNsaWVudCBjYW4gZHJpdmUuIEl0IGRlZmluZXMgdGhlIG1hcC4qIHRvb2wgaWRzXG4gKiBhbmQgdGhlIGBUb29sUmVzdWx0YCBzaGFwZSBzbyBhbnkgaG9zdCAodGhlIGRlbW8tYXBwIGJyb3dzZXIgcGFnZSwgdGhlXG4gKiBrZXBsZXItYXNzaXN0YW50IGxpYnJhcnksIG9yIGEgZnV0dXJlIE1DUCBzZXJ2ZXIpIGNhbiBpbXBsZW1lbnQgb3IgY29uc3VtZVxuICogdGhlIHNhbWUgY29udHJhY3QuXG4gKi9cblxuLyoqIEEgY29tbWFuZC90b29sIGV4ZWN1dGlvbiByZXN1bHQuICovXG5leHBvcnQgaW50ZXJmYWNlIFRvb2xSZXN1bHQge1xuICBzdWNjZXNzOiBib29sZWFuO1xuICBkYXRhPzogdW5rbm93bjtcbiAgZXJyb3I/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogVGhlIHYxIG1hcCB0b29sIHN1cmZhY2UuIFRoZXNlIGFyZSB0aGUgY29tbWFuZCBpZHMgdGhlIGtlcGxlci5nbCBkZW1vLWFwcCdzXG4gKiBhc3Npc3RhbnQgYWN0dWFsbHkgcmVnaXN0ZXJzLCByZWNvbmNpbGVkIHdpdGggdGhlIGtlcGxlci1tY3AgcHJvcG9zYWwuIE1vc3RcbiAqIGNvbW1hbmRzIGFyZSBwdXJlIG1hcCBhY3R1YXRpb24gKHNldC1iYXNlbWFwLCBhZGQtbGF5ZXIsIC4uLik7IHRoZSB0YWJsZSBvcHNcbiAqIChtYXAuY3JlYXRlLXRhYmxlLCBtYXAuYWRkLWNvbHVtbiwgbWFwLnNhdmUtZGF0YSkgYXJlIER1Y2tEQi1iYWNrZWQgYW5kIGFyZVxuICogaW5jbHVkZWQgYmVjYXVzZSB0aGV5IG11dGF0ZSB0aGUgbWFwJ3MgZGF0YXNldHMgaW4gcGxhY2UuXG4gKi9cbmV4cG9ydCBjb25zdCBNQVBfVE9PTF9JRFMgPSBbXG4gICdtYXAuc2V0LWJhc2VtYXAnLFxuICAnbWFwLmdldC1ib3VuZGFyeScsXG4gICdtYXAuYWRkLWxheWVyJyxcbiAgJ21hcC51cGRhdGUtbGF5ZXItY29sb3InLFxuICAnbWFwLmxvYWQtZGF0YScsXG4gICdtYXAuc2F2ZS1kYXRhJyxcbiAgJ21hcC5jcmVhdGUtdGFibGUnLFxuICAnbWFwLmFkZC1jb2x1bW4nLFxuICAnbWFwLmFkZC10aW1lLWZpbHRlcicsXG4gICdtYXAudG9nZ2xlLXRpbWUtZmlsdGVyJyxcbiAgJ21hcC5zcGxpdC12aWV3JyxcbiAgJ21hcC5nZXQtZGF0YXNldC1jb250ZXh0J1xuXSBhcyBjb25zdDtcblxuZXhwb3J0IHR5cGUgTWFwVG9vbElkID0gKHR5cGVvZiBNQVBfVE9PTF9JRFMpW251bWJlcl07XG4iXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQU9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ08sSUFBTUEsWUFBWSxHQUFBQyxPQUFBLENBQUFELFlBQUEsR0FBRyxDQUMxQixpQkFBaUIsRUFDakIsa0JBQWtCLEVBQ2xCLGVBQWUsRUFDZix3QkFBd0IsRUFDeEIsZUFBZSxFQUNmLGVBQWUsRUFDZixrQkFBa0IsRUFDbEIsZ0JBQWdCLEVBQ2hCLHFCQUFxQixFQUNyQix3QkFBd0IsRUFDeEIsZ0JBQWdCLEVBQ2hCLHlCQUF5QixDQUNqQiIsImlnbm9yZUxpc3QiOltdfQ==
@@ -0,0 +1,4 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ export declare const addColumnCommandId: "map.add-column";
4
+ export declare function getAddColumnCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,4 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ export declare const basemapCommandId: "map.set-basemap";
4
+ export declare function getBasemapCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,4 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ export declare const mapBoundaryCommandId: "map.get-boundary";
4
+ export declare function getMapBoundaryCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Generic utility for converting an existing AI SDK tool into a sqlrooms
3
+ * `RoomCommand`. Kept dependency-light (only `zod` + `RoomCommand` type) so it
4
+ * can be reused by any in-browser skill system that wants to expose its
5
+ * existing AI SDK tools as commands without rewriting them.
6
+ *
7
+ * The demo-app's own command factories return `RoomCommand` directly (preferred
8
+ * when you own the command — see `basemap-command.ts` for the reference shape). This
9
+ * wrapper is the fallback path for hosts that cannot rewrite their tools:
10
+ * it folds the tool's `execute`, `inputSchema`, and `toModelOutput` (the
11
+ * token-trim logic the AI SDK applies between tool call and model) into a
12
+ * single `RoomCommand.execute` so the registry-stored result already carries
13
+ * the model-facing subset.
14
+ */
15
+ import type { RoomCommand } from './types';
16
+ import type { ZodType } from 'zod';
17
+ /** A built AI SDK tool, treated loosely for dynamic dispatch. */
18
+ export type AnyTool = {
19
+ execute?: (args: any, options: any) => Promise<any>;
20
+ toModelOutput?: (params: {
21
+ output: any;
22
+ toolCallId?: string;
23
+ }) => any;
24
+ description?: string;
25
+ inputSchema?: ZodType;
26
+ };
27
+ /** Metadata that the AI SDK tool does not carry but a `RoomCommand` requires. */
28
+ export type CommandMeta = {
29
+ /** Stable, namespaced command id, e.g. `map.set-basemap`. */
30
+ id: string;
31
+ /** Human-readable name shown in the command palette / listings. */
32
+ name: string;
33
+ /** Optional grouping label, e.g. `Map`, `Data`, `GeoDa`. */
34
+ group?: string;
35
+ /** Optional search keywords. */
36
+ keywords?: string[];
37
+ };
38
+ /**
39
+ * Cast a concrete zod schema (e.g. `z.object({...})`, which is `ZodObject<...>`)
40
+ * to the `ZodType<unknown>` that `RoomCommand.inputSchema` expects. The
41
+ * installed zod `ZodObject` is not structurally assignable to sqlrooms'
42
+ * `ZodType<unknown>` (covariance on the output type), so a cast is required at
43
+ * the assignment site. This helper centralizes that cast.
44
+ */
45
+ export declare function asInputSchema(schema: ZodType): ZodType<unknown>;
46
+ /**
47
+ * Wrap an existing AI SDK tool as a sqlrooms `RoomCommand`. The command's
48
+ * `execute` calls the tool's `execute` and then applies the tool's
49
+ * `toModelOutput` (if any) so the trimmed, model-facing shape is what the
50
+ * registry stores and downstream surfaces (AI skill, palette, CLI, MCP) see.
51
+ */
52
+ export declare function toolToCommand(tool: AnyTool, meta: CommandMeta): RoomCommand;
@@ -0,0 +1,4 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ export declare const datasetContextCommandId: "map.get-dataset-context";
4
+ export declare function getDatasetContextCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,31 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ /**
4
+ * Owner string under which all kepler-ai commands are registered in the
5
+ * room-store command registry. Used by `registerCommandsForOwner` /
6
+ * `unregisterCommandsForOwner` in the host's store wiring.
7
+ */
8
+ export declare const KEPLER_COMMAND_OWNER = "kepler-ai";
9
+ /**
10
+ * Build the kepler-gl map-mutation commands for a given `KeplerContext`.
11
+ * Returns a map keyed by command id (e.g. `map.set-basemap`) so the registry
12
+ * registration is a flat merge.
13
+ */
14
+ export declare function getKeplerCommands(ctx: KeplerContext): Record<string, RoomCommand>;
15
+ export { getBasemapCommand } from './basemap-command';
16
+ export { getViewModeCommand } from './view-mode-command';
17
+ export { getMapBoundaryCommand } from './boundary-command';
18
+ export { getAddLayerCommand, guessDefaultLayer } from './layer-creation-command';
19
+ export { getUpdateLayerColorCommand } from './layer-style-command';
20
+ export { getLoadDataCommand } from './load-data-command';
21
+ export { getSaveDataCommand } from './save-data-command';
22
+ export { getTableCommand } from './table-command';
23
+ export { getAddColumnCommand } from './add-column-command';
24
+ export { getAddTimeFilterCommand } from './time-filter-command';
25
+ export { getToggleTimeFilterCommand } from './toggle-time-filter-command';
26
+ export { getSplitViewCommand } from './split-view-command';
27
+ export { getDatasetContextCommand } from './dataset-context-command';
28
+ export { toolToCommand, asInputSchema } from './command-wrappers';
29
+ export type { AnyTool, CommandMeta } from './command-wrappers';
30
+ export type { KeplerContext, KeplerStateAccessors, VisState, RoomCommandResult, RoomCommandExecuteOutput, ToolDescriptor } from './types';
31
+ export { datasetNameToTableName, convertArrowRowToObject, arrowTableToObjects, tableToLLMResult, formatResultsForLLM, NUMBER_OF_ROWS_RETURN_TO_LLM, LLM_PREVIEW_MAX_TOTAL_LENGTH, LLM_PREVIEW_MAX_VALUE_LENGTH, getValuesFromDataset, getValuesFromVectorTileLayer, isObjectColumn, isVectorTileLayer, stringifyObjectColumn, restoreObjectColumns, buildAddColumnPayload } from './utils';
@@ -0,0 +1,8 @@
1
+ import type { RoomCommand } from './types';
2
+ import type KeplerTable from '@kepler.gl/table';
3
+ import type { KeplerContext } from './types';
4
+ export declare function guessDefaultLayer(dataset: KeplerTable, layerType: string, options?: {
5
+ countColumn?: string;
6
+ }): any;
7
+ export declare const addLayerCommandId: "map.add-layer";
8
+ export declare function getAddLayerCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,4 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ export declare const updateLayerColorCommandId: "map.update-layer-color";
4
+ export declare function getUpdateLayerColorCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,4 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ export declare const loadDataCommandId: "map.load-data";
4
+ export declare function getLoadDataCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,4 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ export declare const saveDataCommandId: "map.save-data";
4
+ export declare function getSaveDataCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,4 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ export declare const splitViewCommandId: "map.split-view";
4
+ export declare function getSplitViewCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,4 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ export declare const tableCommandId: "map.create-table";
4
+ export declare function getTableCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,13 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ export type IntervalKey = '1-second' | '1-minute' | '1-hour' | '1-day' | '1-week' | '1-month' | '3-month' | '1-year';
4
+ export declare const INTERVAL_MILLIS: Record<IntervalKey, number>;
5
+ /**
6
+ * Infer a sensible animation interval from a time filter's domain and (when
7
+ * available) the actual distinct timestamps in the dataset. Mirrors the logic
8
+ * used by spatial-agent's `detectIntervalFromDomain` so the skill-path behaves
9
+ * identically.
10
+ */
11
+ export declare function detectIntervalFromDomain(domain: [number, number], mappedValues?: number[]): IntervalKey;
12
+ export declare const addTimeFilterCommandId: "map.add-time-filter";
13
+ export declare function getAddTimeFilterCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,4 @@
1
+ import type { RoomCommand } from './types';
2
+ import type { KeplerContext } from './types';
3
+ export declare const toggleTimeFilterCommandId: "map.toggle-time-filter";
4
+ export declare function getToggleTimeFilterCommand(ctx: KeplerContext): RoomCommand;
@@ -0,0 +1,132 @@
1
+ import type { Table as ArrowTable } from 'apache-arrow';
2
+ import type { ZodType } from 'zod';
3
+ import type { Datasets } from '@kepler.gl/table';
4
+ import type { KeplerDispatch } from './utils';
5
+ /**
6
+ * Structural subset of `@sqlrooms/room-store`'s `RoomCommand` — enough for the
7
+ * map.* command factories and for a host to register the built objects. Defined
8
+ * locally (with `zod`, already a dependency) so this package stays free of
9
+ * `@sqlrooms/room-store`; the objects the factories build are structurally
10
+ * compatible with sqlrooms' own `RoomCommand`.
11
+ */
12
+ export type RoomCommandResult<TData = unknown> = {
13
+ success: boolean;
14
+ commandId: string;
15
+ message?: string;
16
+ code?: string;
17
+ data?: TData;
18
+ error?: string;
19
+ };
20
+ export type RoomCommandExecuteOutput<TData = unknown> = RoomCommandResult<TData> | TData | void;
21
+ export type RoomCommandExecutionContext = {
22
+ store: unknown;
23
+ getState: () => unknown;
24
+ invocation: unknown;
25
+ signal?: AbortSignal;
26
+ };
27
+ export type RoomCommandPolicyMetadata = {
28
+ readOnly?: boolean;
29
+ idempotent?: boolean;
30
+ riskLevel?: 'low' | 'medium' | 'high';
31
+ requiresConfirmation?: boolean;
32
+ };
33
+ export type RoomCommand = {
34
+ id: string;
35
+ name: string;
36
+ description?: string;
37
+ group?: string;
38
+ keywords?: string[];
39
+ inputSchema?: ZodType<unknown>;
40
+ metadata?: RoomCommandPolicyMetadata;
41
+ execute: (context: RoomCommandExecutionContext, input?: unknown) => RoomCommandExecuteOutput | Promise<RoomCommandExecuteOutput>;
42
+ };
43
+ /**
44
+ * A command's model-facing descriptor: the id/name/description/group/keywords
45
+ * plus a JSON-Schema-converted `inputSchema` and the policy metadata. This is
46
+ * the shape hosts advertise over the wire (e.g. the demo-app bridge's
47
+ * `toDescriptor`), so it lives in the map surface package to keep the contract
48
+ * self-contained.
49
+ */
50
+ export type ToolDescriptor = {
51
+ id: string;
52
+ name: string;
53
+ description?: string;
54
+ group?: string;
55
+ keywords?: string[];
56
+ inputSchema: Record<string, unknown>;
57
+ metadata?: RoomCommandPolicyMetadata;
58
+ };
59
+ /**
60
+ * Structural slice of `@sqlrooms/duckdb`'s `DuckDbConnector` — only the methods
61
+ * the map.* commands call, typed against apache-arrow so the query result flows
62
+ * into `arrowTableToObjects` / `arrowSchemaToFields` unchanged. Kept local so
63
+ * this package needs no `@sqlrooms/duckdb` dependency; a host's real sqlrooms
64
+ * connector satisfies this shape.
65
+ */
66
+ export type DuckDbConnector = {
67
+ execute(sql: string, options?: {
68
+ signal?: AbortSignal;
69
+ }): PromiseLike<unknown>;
70
+ query(sql: string, options?: {
71
+ signal?: AbortSignal;
72
+ }): PromiseLike<ArrowTable>;
73
+ loadArrow(table: ArrowTable | Uint8Array, tableName: string, opts?: {
74
+ schema?: string;
75
+ }): Promise<void>;
76
+ };
77
+ export type VisState = {
78
+ datasets: Datasets;
79
+ layers: any[];
80
+ layerData: any[];
81
+ loaders: any[];
82
+ loadOptions: Record<string, any>;
83
+ [key: string]: any;
84
+ };
85
+ /**
86
+ * Accessors to the kepler.gl application state the assistant needs. The host
87
+ * app supplies these (via `setKeplerStateAccessors`) so this module never
88
+ * hard-codes a redux state shape (e.g. `demo.keplerGl.map.visState`). Any
89
+ * app can provide accessors matching its own store.
90
+ */
91
+ export type KeplerStateAccessors = {
92
+ getVisState: () => VisState;
93
+ getMapBoundary: () => {
94
+ nw: [number, number];
95
+ se: [number, number];
96
+ } | undefined;
97
+ };
98
+ /**
99
+ * KeplerContext provides access to kepler.gl state and dispatch.
100
+ * This is passed into tool factories instead of using Redux directly.
101
+ *
102
+ * The four glue methods (`getValuesFromDataset`, `getDatasetContext`,
103
+ * `loadTableToKepler`, `loadTableIntoDuckDB`, `getConnector`) are the
104
+ * kepler-app-bound seam the map.* commands call. They are implemented by the
105
+ * host's glue (kepler-assistant) so this package stays free of the DuckDB /
106
+ * kepler-app wiring.
107
+ */
108
+ export type KeplerContext = {
109
+ getVisState: () => VisState;
110
+ getMapBoundary: () => {
111
+ nw: [number, number];
112
+ se: [number, number];
113
+ } | undefined;
114
+ getMapboxToken: () => string | undefined;
115
+ dispatch: KeplerDispatch;
116
+ /** Read a column's values from a kepler dataset (by label or id). */
117
+ getValuesFromDataset: (datasetName: string, variableName: string) => unknown[];
118
+ /** Build the dataset+layer context string for the LLM. */
119
+ getDatasetContext: () => string;
120
+ /** Load a DuckDB table into kepler.gl as a dataset. */
121
+ loadTableToKepler: (tableName: string, options?: {
122
+ autoCreateLayers?: boolean;
123
+ centerMap?: boolean;
124
+ }) => Promise<{
125
+ success: boolean;
126
+ error?: string;
127
+ }>;
128
+ /** Materialize a kepler dataset's columns into a DuckDB table and return the connector. */
129
+ loadTableIntoDuckDB: (datasetName: string, variableNames: string[], dbTableName: string) => Promise<DuckDbConnector>;
130
+ /** The shared DuckDB connector (the store's, when wired). */
131
+ getConnector: () => Promise<DuckDbConnector>;
132
+ };