gibson-cli 0.8.9__py3-none-any.whl → 0.8.11__py3-none-any.whl

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.
gibson/api/ProjectApi.py CHANGED
@@ -1,3 +1,5 @@
1
+ from typing import List
2
+
1
3
  from gibson.api.BaseApi import BaseApi
2
4
  from gibson.core.Configuration import Configuration
3
5
 
@@ -20,8 +22,13 @@ class ProjectApi(BaseApi):
20
22
  def lookup(self, uuid: str):
21
23
  return self.get(f"{uuid}")
22
24
 
23
- def deploy(self, uuid: str):
24
- return self.post(f"{uuid}/deploy")
25
+ def deploy(self, uuid: str, databases: List[str] | None = None):
26
+ return self.post(
27
+ f"{uuid}/deploy", {"environments": databases} if databases else None
28
+ )
29
+
30
+ def diff(self, uuid: str):
31
+ return self.get(f"{uuid}/diff")
25
32
 
26
33
  def mcp(self, uuid: str):
27
34
  return self.get(f"{uuid}/mcp")
@@ -0,0 +1,52 @@
1
+ from rich.prompt import Confirm
2
+
3
+ from gibson.api.ProjectApi import ProjectApi
4
+ from gibson.command.BaseCommand import BaseCommand
5
+ from gibson.core.Select import MultiSelect
6
+ from gibson.core.Spinner import Spinner
7
+
8
+
9
+ class Deploy(BaseCommand):
10
+ def execute(self):
11
+ self.configuration.require_login()
12
+ project_id = self.configuration.require_project_id()
13
+ project = ProjectApi(self.configuration).lookup(project_id)
14
+ databases = [database["environment"] for database in project["databases"]]
15
+
16
+ selected = MultiSelect(
17
+ title="Select the database(s) to deploy",
18
+ options=databases,
19
+ ).prompt()
20
+
21
+ if not selected:
22
+ self.conversation.type("No database selected\n")
23
+ exit(1)
24
+
25
+ for database in selected:
26
+ diff = ProjectApi(self.configuration).diff(project_id)
27
+ if diff:
28
+ self.conversation.type(f"\nDiff for {database} database:\n\n")
29
+ self.conversation.type(diff)
30
+ self.conversation.newline()
31
+
32
+ if Confirm.ask(
33
+ f"After reviewing the diff, are you sure you want to deploy the {database} database?"
34
+ ):
35
+ self.conversation.newline()
36
+ with Spinner(
37
+ start_text=f"Deploying {database} database...",
38
+ success_text=f"Deployed {database} database",
39
+ fail_text=f"Deployment failed for {database} database",
40
+ ):
41
+ ProjectApi(self.configuration).deploy(
42
+ project_id, databases=[database]
43
+ )
44
+
45
+ else:
46
+ self.conversation.type(
47
+ f"\nSkipping deployment for {database} database\n",
48
+ )
49
+ else:
50
+ self.conversation.type(
51
+ f"\nNo changes to deploy for {database} database\n",
52
+ )
gibson/command/Help.py CHANGED
@@ -4,7 +4,6 @@ from rich.table import Table
4
4
  from rich.text import Text
5
5
 
6
6
  from gibson.command.BaseCommand import BaseCommand
7
- from gibson.core.Memory import Memory
8
7
 
9
8
 
10
9
  class Help(BaseCommand):
@@ -25,27 +24,26 @@ class Help(BaseCommand):
25
24
  "auth": {
26
25
  "description": "authenticate with the gibson cli",
27
26
  "subcommands": ["login", "logout"],
28
- "memory": None,
29
27
  },
30
28
  "build": {
31
29
  "description": "create the entities in the datastore",
32
30
  "subcommands": ["datastore"],
33
- "memory": "stored",
34
31
  },
35
32
  "code": {
36
33
  "description": "pair program with gibson",
37
34
  "subcommands": ["api", "base", "entity", "models", "schemas", "tests"],
38
- "memory": None,
39
35
  },
40
36
  "conf": {
41
37
  "description": "set a configuration variable",
42
38
  "subcommands": None,
43
- "memory": None,
44
39
  },
45
40
  "count": {
46
41
  "description": "show the number of entities stored",
47
42
  "subcommands": ["last", "stored"],
48
- "memory": "based on user selection",
43
+ },
44
+ "deploy": {
45
+ "description": "deploy the project database(s) with the current schema",
46
+ "subcommands": None,
49
47
  },
50
48
  "dev": {
51
49
  "description": Text.assemble(
@@ -53,73 +51,55 @@ class Help(BaseCommand):
53
51
  *dev_mode_text,
54
52
  ),
55
53
  "subcommands": ["on", "off"],
56
- "memory": None,
57
- },
58
- "forget": {
59
- "description": "delete entities from memory",
60
- "subcommands": ["all", "last", "stored"],
61
- "memory": "based on user selection",
62
54
  },
63
- "help": {"description": "for help", "subcommands": None, "memory": None},
55
+ "help": {"description": "for help", "subcommands": None},
64
56
  "import": {
65
57
  "description": "import entities from a datasource",
66
58
  "subcommands": ["api", "mysql", "pg_dump", "openapi"],
67
- "memory": "stored",
68
59
  },
69
60
  "list": {
70
61
  "description": "see a list of your entities or projects",
71
62
  "subcommands": ["entities", "projects"],
72
- "memory": None,
73
63
  },
74
64
  "mcp": {
75
65
  "description": "allows tools like Cursor to interact with your gibson project",
76
66
  "subcommands": ["run"],
77
- "memory": None,
78
- },
79
- "merge": {
80
- "description": "merge last memory (recent changes) into stored project memory",
81
- "subcommands": None,
82
- "memory": "last -> stored",
83
67
  },
84
68
  "modify": {
85
69
  "description": "change an entity using natural language",
86
70
  "subcommands": None,
87
- "memory": "last > stored",
88
71
  },
89
72
  "new": {
90
73
  "description": "create something new",
91
74
  "subcommands": ["project", "module", "entity"],
92
- "memory": None,
93
75
  },
94
76
  "remove": {
95
77
  "description": "remove an entity from the project",
96
78
  "subcommands": None,
97
- "memory": "last > stored",
98
79
  },
99
80
  "rename": {
100
81
  "description": "rename an entity",
101
82
  "subcommands": ["entity"],
102
- "memory": "last > stored",
103
83
  },
104
84
  "rewrite": {
105
85
  "description": "rewrite all code",
106
86
  "subcommands": None,
107
- "memory": "stored",
108
87
  },
109
88
  "show": {
110
89
  "description": "display an entity",
111
90
  "subcommands": None,
112
- "memory": "last > stored",
91
+ },
92
+ "studio": {
93
+ "description": "connect to your database and launch the SQL studio",
94
+ "subcommands": None,
113
95
  },
114
96
  "tree": {
115
97
  "description": "illustrate the project layout in a tree view",
116
98
  "subcommands": None,
117
- "memory": None,
118
99
  },
119
100
  "q": {
120
- "description": "ask gibson a question using natural language",
101
+ "description": "chat with gibson",
121
102
  "subcommands": None,
122
- "memory": None,
123
103
  },
124
104
  }
125
105
 
@@ -142,7 +122,6 @@ class Help(BaseCommand):
142
122
  help.add_column("command", style="yellow bold", header_style="yellow bold")
143
123
  help.add_column("description")
144
124
  help.add_column("subcommands", header_style="magenta")
145
- help.add_column("memory affected", style="grey50", header_style="grey50")
146
125
 
147
126
  for subcommand, config in subcommands.items():
148
127
  help.add_row(
@@ -155,26 +134,8 @@ class Help(BaseCommand):
155
134
  if config["subcommands"]
156
135
  else ""
157
136
  ),
158
- config["memory"] or "",
159
137
  )
160
138
 
161
139
  console.print(help)
162
140
 
163
141
  self.conversation.newline()
164
-
165
- if self.configuration.project:
166
- stats = Memory(self.configuration).stats()
167
- memory = Table(
168
- title="Memory",
169
- show_header=True,
170
- header_style="bold",
171
- box=box.ROUNDED,
172
- expand=True,
173
- )
174
- memory.add_column("stored", style="green", header_style="green")
175
- memory.add_column("last", style="yellow", header_style="yellow")
176
- memory.add_row(
177
- f"{stats['entities']['num']} {stats['entities']['word']}",
178
- f"{stats['last']['num']} {stats['last']['word']}",
179
- )
180
- console.print(memory)
@@ -0,0 +1,58 @@
1
+ from urllib.parse import urlparse
2
+
3
+ from harlequin.app import Harlequin
4
+ from harlequin.plugins import load_adapter_plugins
5
+
6
+ from gibson.api.ProjectApi import ProjectApi
7
+ from gibson.command.BaseCommand import BaseCommand
8
+ from gibson.core.Select import Select
9
+ from gibson.core.Spinner import DisappearingSpinner
10
+
11
+
12
+ class Studio(BaseCommand):
13
+ def execute(self):
14
+ self.configuration.require_login()
15
+ project_id = self.configuration.require_project_id()
16
+
17
+ project = ProjectApi(self.configuration).lookup(project_id)
18
+
19
+ choices = [database["environment"] for database in project["databases"]]
20
+
21
+ selected = Select(
22
+ title="Select a database",
23
+ options=choices,
24
+ ).prompt()
25
+
26
+ if not selected:
27
+ self.conversation.type("No database selected\n")
28
+ exit(1)
29
+
30
+ database = next(
31
+ (db for db in project["databases"] if db["environment"] == selected), None
32
+ )
33
+
34
+ with DisappearingSpinner(
35
+ start_text=f"Connecting to {database['environment']} database...",
36
+ success_text=f"Connected to {database['environment']} database",
37
+ fail_text=f"Failed to connect to {database['environment']} database",
38
+ ):
39
+ plugins = load_adapter_plugins()
40
+ adapter = plugins[database["datastore_type"]]
41
+
42
+ if database["datastore_type"] == "mysql":
43
+ connection = urlparse(database["connection_string"])
44
+ adapter = adapter(
45
+ conn_str=None,
46
+ host=connection.hostname,
47
+ port=connection.port,
48
+ user=connection.username,
49
+ password=connection.password,
50
+ database=connection.path.lstrip("/"),
51
+ )
52
+ else:
53
+ raise ValueError(
54
+ f"Unsupported database type: {database['datastore_type']}"
55
+ )
56
+
57
+ app = Harlequin(adapter=adapter)
58
+ app.run()
gibson/command/Version.py CHANGED
@@ -21,7 +21,7 @@ class Version(BaseCommand):
21
21
  f"You are currently using version: {Colors.violet(VersionConf.num)}\n"
22
22
  )
23
23
  self.conversation.type(
24
- f"Please update to the latest version by running: {Colors.command('pip3', 'install', args='--upgrade', inputs='gibson-cli')}\n"
24
+ f"Please update to the latest version by running: {Colors.command('uv', 'tool', args='install', inputs='gibson-cli@latest')}\n"
25
25
  )
26
26
  else:
27
27
  self.conversation.type(
@@ -5,13 +5,12 @@ from gibson.command.Build import Build
5
5
  from gibson.command.code.Code import Code
6
6
  from gibson.command.Conf import Conf
7
7
  from gibson.command.Count import Count
8
+ from gibson.command.Deploy import Deploy
8
9
  from gibson.command.Dev import Dev
9
- from gibson.command.Forget import Forget
10
10
  from gibson.command.Help import Help
11
11
  from gibson.command.importer.Import import Import
12
12
  from gibson.command.list.List import List
13
13
  from gibson.command.mcp.McpServer import McpServer
14
- from gibson.command.Merge import Merge
15
14
  from gibson.command.Modify import Modify
16
15
  from gibson.command.new.New import New
17
16
  from gibson.command.Question import Question
@@ -19,6 +18,7 @@ from gibson.command.Remove import Remove
19
18
  from gibson.command.rename.Rename import Rename
20
19
  from gibson.command.rewrite.Rewrite import Rewrite
21
20
  from gibson.command.Show import Show
21
+ from gibson.command.Studio import Studio
22
22
  from gibson.command.Tree import Tree
23
23
  from gibson.command.Version import Version
24
24
  from gibson.core.Configuration import Configuration
@@ -52,10 +52,10 @@ class CommandRouter:
52
52
  command = Conf(self.configuration)
53
53
  elif sys.argv[1] == "count":
54
54
  command = Count(self.configuration)
55
+ elif sys.argv[1] == "deploy":
56
+ command = Deploy(self.configuration)
55
57
  elif sys.argv[1] == "dev":
56
58
  command = Dev(self.configuration)
57
- elif sys.argv[1] == "forget":
58
- command = Forget(self.configuration)
59
59
  elif sys.argv[1] == "help":
60
60
  command = Help(self.configuration)
61
61
  elif sys.argv[1] == "import":
@@ -64,8 +64,6 @@ class CommandRouter:
64
64
  command = List(self.configuration)
65
65
  elif sys.argv[1] == "mcp":
66
66
  command = McpServer(self.configuration)
67
- elif sys.argv[1] == "merge":
68
- command = Merge(self.configuration)
69
67
  elif sys.argv[1] == "modify":
70
68
  command = Modify(self.configuration)
71
69
  elif sys.argv[1] == "new":
@@ -78,6 +76,8 @@ class CommandRouter:
78
76
  command = Rewrite(self.configuration, with_header=True)
79
77
  elif sys.argv[1] == "show":
80
78
  command = Show(self.configuration)
79
+ elif sys.argv[1] == "studio":
80
+ command = Studio(self.configuration)
81
81
  elif sys.argv[1] == "tree":
82
82
  command = Tree(self.configuration)
83
83
  elif sys.argv[1] in ["q"]:
@@ -237,6 +237,10 @@ class Configuration:
237
237
  return self.settings[self.project.name]
238
238
 
239
239
  def get_project_id(self):
240
+ project_id = os.getenv("GIBSONAI_PROJECT_ID")
241
+ if project_id:
242
+ return project_id
243
+
240
244
  self.require_project()
241
245
  return self.project.id
242
246
 
gibson/core/Select.py ADDED
@@ -0,0 +1,270 @@
1
+ from typing import Any, List, Optional
2
+
3
+ import click
4
+ from rich.align import Align
5
+ from rich.console import Group
6
+ from rich.live import Live
7
+ from rich.panel import Panel
8
+ from rich.text import Text
9
+
10
+
11
+ class BaseSelect:
12
+ """Base class for select components with shared functionality."""
13
+
14
+ def __init__(
15
+ self,
16
+ options: List[str] = [],
17
+ title: str = "",
18
+ color: str = "bold magenta",
19
+ align: str = "left",
20
+ selection: str = "→",
21
+ highlight: str = "green",
22
+ ):
23
+ self.options = options
24
+ self.index = 0
25
+ self.title = title
26
+ self.color = color
27
+ self.align = align
28
+ self.selection = selection
29
+ self.highlight = highlight
30
+
31
+ def _get_click(self) -> Optional[str]:
32
+ match click.getchar():
33
+ case "\r":
34
+ return "enter"
35
+ case "\x1b[B" | "s" | "S" | "àP":
36
+ return "down"
37
+ case "\x1b[A" | "w" | "W" | "àH":
38
+ return "up"
39
+ case "\x1b[D" | "a" | "A" | "àK":
40
+ return "left"
41
+ case "\x1b[C" | "d" | "D" | "àM":
42
+ return "right"
43
+ case "\x1b":
44
+ return "exit"
45
+ case _:
46
+ return None
47
+
48
+ def _set_index(self, key: str) -> None:
49
+ if key == "down":
50
+ self.index += 1
51
+ elif key == "up":
52
+ self.index -= 1
53
+
54
+ if self.index > len(self.options) - 1:
55
+ self.index = 0
56
+ elif self.index < 0:
57
+ self.index = len(self.options) - 1
58
+
59
+ def _clear(self) -> None:
60
+ for _ in range(len(self.options) + 5):
61
+ print("\x1b[A\x1b[K", end="")
62
+
63
+ @property
64
+ def _usage_info(self) -> Text:
65
+ """Return usage information text for the select menu."""
66
+ return Text("Use ↑/↓ to navigate, ENTER to submit", "dim")
67
+
68
+ @property
69
+ def _layout(self) -> Group:
70
+ """Generate the display group for the menu.
71
+ This method should be overridden by subclasses.
72
+ """
73
+ raise NotImplementedError("Subclasses must implement _layout")
74
+
75
+ @property
76
+ def _panel_width(self) -> int:
77
+ """Return the width of the panel."""
78
+ # Calculate minimum width needed for the usage text
79
+ usage_width = len(self._usage_info.plain) + 2
80
+ # Get the max width of options
81
+ options_width = (
82
+ max((len(option) for option in self.options), default=0) + 5
83
+ ) # +5 for marker and spacing
84
+ # Use the larger of the two widths, plus some padding
85
+ return max(usage_width, options_width) + 4
86
+
87
+ def prompt(self) -> Any:
88
+ """Display the menu and handle user input.
89
+ This method should be overridden by subclasses.
90
+ """
91
+ raise NotImplementedError("Subclasses must implement prompt")
92
+
93
+
94
+ class Select(BaseSelect):
95
+ def __init__(
96
+ self,
97
+ options: List[str] = [],
98
+ start_index: int = 0,
99
+ title: str = "",
100
+ color: str = "bold magenta",
101
+ align: str = "left",
102
+ selection: str = "→",
103
+ highlight: str = "green",
104
+ ):
105
+ super().__init__(
106
+ options=options,
107
+ title=title,
108
+ color=color,
109
+ align=align,
110
+ selection=selection,
111
+ highlight=highlight,
112
+ )
113
+ self.index = start_index
114
+
115
+ @property
116
+ def _layout(self) -> Group:
117
+ menu = Text(justify="left")
118
+
119
+ selected = Text(self.selection + " ", self.highlight)
120
+ not_selected = Text(" " * (len(self.selection) + 1))
121
+
122
+ for idx, option in enumerate(self.options):
123
+ if idx == self.index:
124
+ menu.append(
125
+ Text.assemble(selected, Text(option + "\n", self.highlight))
126
+ )
127
+ else:
128
+ menu.append(Text.assemble(not_selected, option + "\n"))
129
+
130
+ menu.rstrip()
131
+
132
+ menu = Panel(menu, padding=1, width=self._panel_width)
133
+ menu.title = Text(self.title, self.color)
134
+ menu.subtitle = self._usage_info
135
+
136
+ return Group(Align(menu, self.align))
137
+
138
+ def prompt(self) -> str:
139
+ with Live(self._layout, auto_refresh=False, screen=False) as live:
140
+ live.update(self._layout, refresh=True)
141
+ while True:
142
+ try:
143
+ key = self._get_click()
144
+ if key == "enter":
145
+ break
146
+ elif key == "exit":
147
+ exit()
148
+
149
+ self._set_index(key)
150
+ live.update(self._layout, refresh=True)
151
+ except (KeyboardInterrupt, EOFError):
152
+ exit()
153
+
154
+ self._clear()
155
+
156
+ return self.options[self.index]
157
+
158
+
159
+ class MultiSelect(BaseSelect):
160
+ def __init__(
161
+ self,
162
+ options: List[str] = [],
163
+ start_indices: Optional[List[int]] = None,
164
+ title: str = "",
165
+ color: str = "bold magenta",
166
+ align: str = "left",
167
+ selection: str = "→",
168
+ highlight: str = "green",
169
+ selected_marker: str = "●",
170
+ unselected_marker: str = "○",
171
+ ):
172
+ super().__init__(
173
+ options=options,
174
+ title=title,
175
+ color=color,
176
+ align=align,
177
+ selection=selection,
178
+ highlight=highlight,
179
+ )
180
+ self.selected_indices = start_indices or []
181
+ self.selected_marker = selected_marker
182
+ self.unselected_marker = unselected_marker
183
+
184
+ def _get_click(self) -> Optional[str]:
185
+ # Override to add space key handling
186
+ match click.getchar():
187
+ case "\r":
188
+ return "enter"
189
+ case "\x1b[B" | "s" | "S" | "àP":
190
+ return "down"
191
+ case "\x1b[A" | "w" | "W" | "àH":
192
+ return "up"
193
+ case "\x1b[D" | "a" | "A" | "àK":
194
+ return "left"
195
+ case "\x1b[C" | "d" | "D" | "àM":
196
+ return "right"
197
+ case " ":
198
+ return "space"
199
+ case "\x1b":
200
+ return "exit"
201
+ case _:
202
+ return None
203
+
204
+ def _toggle_selection(self) -> None:
205
+ if self.index in self.selected_indices:
206
+ self.selected_indices.remove(self.index)
207
+ else:
208
+ self.selected_indices.append(self.index)
209
+
210
+ @property
211
+ def _usage_info(self) -> Text:
212
+ """Return usage information text for the multi-select menu."""
213
+ return Text("Use ↑/↓ to navigate, SPACE to toggle, ENTER to submit", "dim")
214
+
215
+ @property
216
+ def _layout(self) -> Group:
217
+ menu = Text(justify="left")
218
+
219
+ cursor_selected = Text(self.selection + " ", self.highlight)
220
+ cursor_not_selected = Text(" " * (len(self.selection) + 1))
221
+
222
+ for idx, option in enumerate(self.options):
223
+ # Determine if this option is selected
224
+ marker = (
225
+ self.selected_marker
226
+ if idx in self.selected_indices
227
+ else self.unselected_marker
228
+ )
229
+
230
+ # Determine if cursor is on this item
231
+ if idx == self.index:
232
+ menu.append(
233
+ Text.assemble(
234
+ cursor_selected, Text(f"{marker} {option}\n", self.highlight)
235
+ )
236
+ )
237
+ else:
238
+ menu.append(Text.assemble(cursor_not_selected, f"{marker} {option}\n"))
239
+
240
+ menu.rstrip()
241
+
242
+ menu = Panel(menu, padding=1, width=self._panel_width)
243
+ menu.title = Text(self.title, self.color)
244
+ menu.subtitle = self._usage_info
245
+
246
+ return Group(Align(menu, self.align))
247
+
248
+ def prompt(self) -> List[str]:
249
+ with Live(self._layout, auto_refresh=False, screen=False) as live:
250
+ live.update(self._layout, refresh=True)
251
+ while True:
252
+ try:
253
+ key = self._get_click()
254
+ if key == "enter":
255
+ break
256
+ elif key == "exit":
257
+ exit()
258
+ elif key == "space":
259
+ self._toggle_selection()
260
+ live.update(self._layout, refresh=True)
261
+ else:
262
+ self._set_index(key)
263
+ live.update(self._layout, refresh=True)
264
+ except (KeyboardInterrupt, EOFError):
265
+ exit()
266
+
267
+ self._clear()
268
+
269
+ # Return the selected options
270
+ return [self.options[i] for i in self.selected_indices]
@@ -121,16 +121,17 @@ def submit_data_modeling_request(uuid: str, data_modeling_request: str) -> Dict:
121
121
 
122
122
 
123
123
  @mcp.tool()
124
- def deploy_project(uuid: str) -> None:
124
+ def deploy_project(uuid: str, databases: List[str]) -> None:
125
125
  """
126
- Deploy a GibsonAI project's hosted databases.
126
+ Deploy a GibsonAI project's database(s).
127
+ This updates the schema of the database(s) to match the project schema and automatically handles necessary schema migrations.
127
128
  <IMPORTANT>
128
- This updates both the development and production database schemas simultaneously by automatically handling necessary schema migrations.
129
+ You must provide the names of the database(s) to deploy.
129
130
  </IMPORTANT>
130
131
  """
131
132
  project_api = ProjectApi(Configuration(interactive=False))
132
133
  try:
133
- return project_api.deploy(uuid=uuid)
134
+ return project_api.deploy(uuid=uuid, databases=databases)
134
135
  except HTTPError as e:
135
136
  return error_handler(e)
136
137
 
@@ -168,9 +169,9 @@ def get_deployed_schema(uuid: str) -> str:
168
169
  @mcp.tool()
169
170
  def query_database(api_key: str, query: str) -> List[Dict] | str | Dict:
170
171
  """
171
- Query a GibsonAI project's hosted database using SQL. The environment-specific API key must be provided.
172
+ Query a GibsonAI project's hosted database using SQL. The database-specific API key must be provided.
172
173
  <IMPORTANT>
173
- If you're not sure which environment to use, ask the user for clarification.
174
+ If you're not sure which database to use, ask the user for clarification.
174
175
  Always use the correct syntax for the database dialect (found in the project details).
175
176
  Always wrap identifiers in the dialect appropriate quotes (backticks for MySQL, double quotes for PostgreSQL).
176
177
  </IMPORTANT>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gibson-cli
3
- Version: 0.8.9
3
+ Version: 0.8.11
4
4
  Summary: Gibson Command Line Interface
5
5
  Author-email: GibsonAI <noc@gibsonai.com>
6
6
  Project-URL: Homepage, https://gibsonai.com/
@@ -27,6 +27,8 @@ Requires-Dist: faker-sqlalchemy==0.10.2208140
27
27
  Requires-Dist: fastapi==0.115.12
28
28
  Requires-Dist: fastapi-cli==0.0.2
29
29
  Requires-Dist: h11==0.14.0
30
+ Requires-Dist: harlequin==2.1.2
31
+ Requires-Dist: harlequin-mysql==1.1.0
30
32
  Requires-Dist: httpcore==1.0.5
31
33
  Requires-Dist: httptools==0.6.4
32
34
  Requires-Dist: httpx==0.27.0
@@ -60,7 +62,7 @@ Requires-Dist: sniffio==1.3.1
60
62
  Requires-Dist: sqlalchemy==1.4.41
61
63
  Requires-Dist: sse-starlette==2.2.1
62
64
  Requires-Dist: starlette==0.46.1
63
- Requires-Dist: textual==0.83.0
65
+ Requires-Dist: textual==0.89.1
64
66
  Requires-Dist: tomli==2.0.1
65
67
  Requires-Dist: typer==0.12.3
66
68
  Requires-Dist: typing-extensions==4.13.0
@@ -72,7 +74,7 @@ Requires-Dist: watchfiles==1.0.5
72
74
  Requires-Dist: websockets==12.0
73
75
  Requires-Dist: yaspin==3.1.0
74
76
 
75
- [![GibsonAI](https://github.com/user-attachments/assets/26bc1002-f878-4995-a6c5-eb8d5eb69c28)](https://gibsonai.com/)
77
+ [![GibsonAI](https://github.com/user-attachments/assets/5d5fd577-c19b-4110-b601-e7f20a3370c8)](https://gibsonai.com/)
76
78
 
77
79
  # Gibson CLI
78
80
 
@@ -4,22 +4,24 @@ bin/release.sh,sha256=6pnY_GctbwF-3sZB67b0nzUlTsxlhY1hqJQoqRutXuw,137
4
4
  gibson/api/BaseApi.py,sha256=Wza4yuLHhFjkPxt2dhtUtM_r9b5IGd72V80VDl7v3Gw,3510
5
5
  gibson/api/Cli.py,sha256=Qcm5NIQ4x1Wn6KfkrAzwvZeWyt-cKF_xD7_lTWL4Lbw,8071
6
6
  gibson/api/DataApi.py,sha256=JZN6q7bO2O87xBCsU9w96NgINOJJZx3d7jOiHoVH1Wo,542
7
- gibson/api/ProjectApi.py,sha256=1_gRAAgaqblV0I0D-R-wwgSQArQ4fSCxTDfTO3zDQzY,1212
7
+ gibson/api/ProjectApi.py,sha256=esi51ABY_-6IvNlm-Cr29EBVHGWnWHJ1WqEgVsEKPMo,1419
8
8
  gibson/bin/gibson.py,sha256=ybtdrqLfmTb-gG2U7kWSHWSZDvc864omYR9vres38ZU,458
9
9
  gibson/command/BaseCommand.py,sha256=0LdxshtNj8sySMSaDFIPooDbdZx0mNMyhCuyqcF4JsU,769
10
10
  gibson/command/Build.py,sha256=nFwYhO5lpq7cM6oSH6nBA2ubW8wW7aJFsXIwjE1F2EY,4382
11
11
  gibson/command/Conf.py,sha256=yuAGL6M8MUURG4hW3MAW043c-h_ALw3FHWbyCOR8YTQ,2375
12
12
  gibson/command/Count.py,sha256=QOagwCwDxUHYPivFntr-RWUmlKWKDHgDIGZBfju6VpY,1040
13
+ gibson/command/Deploy.py,sha256=51EHk-4CZygJcIz9pD-Xnpf1Dat1Qok0OdFLUWfqpuQ,2003
13
14
  gibson/command/Dev.py,sha256=zbZjsgAKAHlNUflEr_Lj2QmRBXNbIGIHrPJ3t5DcFC8,4213
14
15
  gibson/command/Forget.py,sha256=rpUmnHISvQlMgsFwa0p2nndaygy9UvDph3mlOmwlugo,1016
15
- gibson/command/Help.py,sha256=Gih3JVZ3SLXrdZPInZccb-NtlzvSUTbTwW2NztKnrbo,6456
16
+ gibson/command/Help.py,sha256=LASgmDCmXMORKh6R-979UaZ62NkjZ-E3Ukt8CUXwEfs,4856
16
17
  gibson/command/Merge.py,sha256=R5ybMC1tUR5_T8YyUfXutzFa_V9j1_flv0s7KTJRq0M,1061
17
18
  gibson/command/Modify.py,sha256=XgTM6EodL7sVhWrnWuTCDx2PNJw3xo-aKI80HCmSpV8,1171
18
19
  gibson/command/Question.py,sha256=g8SwopbzeG14WWP0bc-fXIDVqOOicMzjC9YXoGd-NxY,3830
19
20
  gibson/command/Remove.py,sha256=Ar8-vSNwmCaBupCLY_rcvyU_kWIILU_qVX5njV-tZVw,2478
20
21
  gibson/command/Show.py,sha256=qkkprY2JhA4qOOhYOwAECDnFZwTdqcsKsG4cwB_b-84,1409
22
+ gibson/command/Studio.py,sha256=ZOcXGzrkGGFYtsrxP0qTeComKfUcpTAZWJ9Njd7JfR4,2019
21
23
  gibson/command/Tree.py,sha256=BeJ_13xrrRCK5FP2rQHWpDKrshVzte-_D1pNG1GXPIw,3056
22
- gibson/command/Version.py,sha256=jxkRdbQiyTdto18RpbL-5vudcbvLLX9kcl8vmkt7USw,1187
24
+ gibson/command/Version.py,sha256=bBVxvVc_QD3mpihGMasLqPkSM4G8lR2p0_gKKzIxuO0,1187
23
25
  gibson/command/auth/Auth.py,sha256=DAvnKq3Ks77QJwuGJCWA9Iv3c0Qq5pHFIpEA-gy6CxM,1086
24
26
  gibson/command/auth/Login.py,sha256=4iv3lm-6QNTgtIaszpphyye4eeYOvjU6Ol6ZLmZQZ1I,337
25
27
  gibson/command/auth/Logout.py,sha256=QwW9pCNi61Ak0-1B-3spd_YlsmLYBxzV4uwyO0RYzxg,252
@@ -66,14 +68,15 @@ gibson/conf/dev/Schema.py,sha256=kOSlX1jEyVb82xd8TO8jEAimLcaefIFJr6d2JYvyTqg,74
66
68
  gibson/conf/tests/test_conf_Dependencies.py,sha256=-MAS3SzB1euHFwFhd0dpyIHYNMYgxEaN2LTeZ1pqc6w,363
67
69
  gibson/conf/tests/test_conf_Platform.py,sha256=Zc53IsZmV-hT9VRrZEPNrsuehSdWnJXWKGMmOhEqWHo,138
68
70
  gibson/core/Colors.py,sha256=sllEmJAb2AAUH0e-ZLP1_C8pfz5U_w0fo5kubSH5g1o,3426
69
- gibson/core/CommandRouter.py,sha256=V7awLSPjOx2GQqJNoHQSFsiA2uFkrxtpysyTDbyPloA,3442
71
+ gibson/core/CommandRouter.py,sha256=V3JHyxA_tQnekRMNUg9qqRNjzpEYvtfx7KqRXsh85-s,3446
70
72
  gibson/core/Completions.py,sha256=a26WRh40UpnTT5HGTPT8TCcL8h80HvvZiTJXZofDjx8,1207
71
- gibson/core/Configuration.py,sha256=Cf1V5H17qibDXKcFt6UoyDczeQR33h8HTuKDk51Cae4,16581
73
+ gibson/core/Configuration.py,sha256=eBGBoCe4rrBxlAUg0-UhKwrQSnyxFoey5jC_FeaGlCI,16689
72
74
  gibson/core/Conversation.py,sha256=KF7YPXijhhz6HOkife__ycHox4WeRKNHIpv3juDPhq0,10237
73
75
  gibson/core/Diff.py,sha256=onUJ5_0_S1vKAY_oFgX4vmwQo4byrnXLV4w7QSNA8fY,1071
74
76
  gibson/core/Env.py,sha256=08dZRHzzR0ahrbM4S0bXC7V1xhYQkT8Zefs00qUHf0U,498
75
77
  gibson/core/Memory.py,sha256=3ItGef4RCfBplbjxhNyid8eiPVKHmW-DKAMFeYujqN0,4063
76
78
  gibson/core/PythonPath.py,sha256=0Pj9VUmN-lbv_jGJjjI9UreU4JCdHPdRHSpxQDBrKQw,1577
79
+ gibson/core/Select.py,sha256=8Ax8-rpK3BNrSAlSSSKpv1_uqQuwfy_4kNz7IJoZkjc,8510
77
80
  gibson/core/Spinner.py,sha256=_BO26dOa3h0ZCNaPgMvwOh7K6DUiDv8LgP7QMR3EvNw,1225
78
81
  gibson/core/TimeKeeper.py,sha256=dSeIgGOQJOi0ULlFGAigroGTBfAZXrvP9a1Op_jIsZ0,300
79
82
  gibson/core/utils.py,sha256=KTnPvA3sUYnLFTZG7Tke5YEdls8Da0rNbeaOm8hapiU,408
@@ -106,7 +109,7 @@ gibson/services/code/customization/CustomizationManager.py,sha256=M2gz98Yo2WTnnh
106
109
  gibson/services/code/customization/Index.py,sha256=4Thf0gZM6VErZJS97w748PRNmHi8QvsyblOLCw1Y_XE,364
107
110
  gibson/services/code/customization/tests/test_code_customization_Authenticator.py,sha256=kKExkLfKPpRA2NQH3fvRCuBEMhCGhR-IvNJqXuyBz3c,1949
108
111
  gibson/services/code/customization/tests/test_code_customization_BaseCustomization.py,sha256=jaEwxxoU7d9ziOtfF21NPmZX2qSRpa-kz_8Ju9BKGts,412
109
- gibson/services/mcp/server.py,sha256=sCludSIuvRaH4d6ERbDrM3GlH-BoiBspqmr5XNr5ZbA,6809
112
+ gibson/services/mcp/server.py,sha256=FAHlFFeP_fSlhxnUrnxIzoPEQOoFqKKRcaOyvZULsx0,6892
110
113
  gibson/structure/Entity.py,sha256=N_Tx8RTs9ySMMgAoR9rVuMcsRgNA7zvNvJBScJLfYE4,675
111
114
  gibson/structure/mysql/Entity.py,sha256=zolt3N_F3WlQtlOqrHflwsJeJ6r6A3MN4LxCzeAbU_k,3693
112
115
  gibson/structure/mysql/testing.py,sha256=al4LI6e3bhjopsR0qTAmaOJyCQXF0_inVQ4xv7VQ6qo,9149
@@ -128,9 +131,8 @@ gibson/structure/tests/test_structure_Entity.py,sha256=askl8w0p1uqET6HKBogJlRcPP
128
131
  gibson/tests/test_Env.py,sha256=DPWmP0-aEelducq9bAwv7rKoY2NjWXUeCrzfJDQkn2M,369
129
132
  gibson/tests/test_Memory.py,sha256=YP7owToABAk_-s7fD5UG0HTc4lamDjdA39JUlLnk3Fg,2574
130
133
  gibson/tests/test_utils.py,sha256=r_y-EG05YTCNtL8MWiAK1KmPsmeoMgypKsQC_lVgOtM,559
131
- venv/bin/activate_this.py,sha256=E1T7r3559tBsyqFpdcQW0HbY7gDvNiIv5Pc6HQ4bpoA,2383
132
- gibson_cli-0.8.9.dist-info/METADATA,sha256=M3ndr7LtsbjmX__89dHsi8f3DVddNDKHxuiSRiSss4o,14574
133
- gibson_cli-0.8.9.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
134
- gibson_cli-0.8.9.dist-info/entry_points.txt,sha256=j5VUvq3AzL21xPvVC24zMoXFt-I5lUWulr66nL3OAPM,50
135
- gibson_cli-0.8.9.dist-info/top_level.txt,sha256=fSV3vegbdbSDwiB6n5z3FCeYwkIonzFrx4ek3F_OSdI,16
136
- gibson_cli-0.8.9.dist-info/RECORD,,
134
+ gibson_cli-0.8.11.dist-info/METADATA,sha256=hpsC-cEM3DJvHfQ4X6cf6wNv47sK2_6mKhK2W3Wb9Sk,14645
135
+ gibson_cli-0.8.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
136
+ gibson_cli-0.8.11.dist-info/entry_points.txt,sha256=j5VUvq3AzL21xPvVC24zMoXFt-I5lUWulr66nL3OAPM,50
137
+ gibson_cli-0.8.11.dist-info/top_level.txt,sha256=RFaUY7VXGiqkMwo1Rj7pM4kGvxkhhnfo-2LmPpuL_fs,11
138
+ gibson_cli-0.8.11.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
venv/bin/activate_this.py DELETED
@@ -1,59 +0,0 @@
1
- # Copyright (c) 2020-202x The virtualenv developers
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining
4
- # a copy of this software and associated documentation files (the
5
- # "Software"), to deal in the Software without restriction, including
6
- # without limitation the rights to use, copy, modify, merge, publish,
7
- # distribute, sublicense, and/or sell copies of the Software, and to
8
- # permit persons to whom the Software is furnished to do so, subject to
9
- # the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be
12
- # included in all copies or substantial portions of the Software.
13
- #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
-
22
- """
23
- Activate virtualenv for current interpreter:
24
-
25
- import runpy
26
- runpy.run_path(this_file)
27
-
28
- This can be used when you must use an existing Python interpreter, not the virtualenv bin/python.
29
- """ # noqa: D415
30
-
31
- from __future__ import annotations
32
-
33
- import os
34
- import site
35
- import sys
36
-
37
- try:
38
- abs_file = os.path.abspath(__file__)
39
- except NameError as exc:
40
- msg = "You must use import runpy; runpy.run_path(this_file)"
41
- raise AssertionError(msg) from exc
42
-
43
- bin_dir = os.path.dirname(abs_file)
44
- base = bin_dir[: -len("bin") - 1] # strip away the bin part from the __file__, plus the path separator
45
-
46
- # prepend bin to PATH (this file is inside the bin directory)
47
- os.environ["PATH"] = os.pathsep.join([bin_dir, *os.environ.get("PATH", "").split(os.pathsep)])
48
- os.environ["VIRTUAL_ENV"] = base # virtual env is right above bin directory
49
- os.environ["VIRTUAL_ENV_PROMPT"] = "" or os.path.basename(base) # noqa: SIM222
50
-
51
- # add the virtual environments libraries to the host python import mechanism
52
- prev_length = len(sys.path)
53
- for lib in "../lib/python3.10/site-packages".split(os.pathsep):
54
- path = os.path.realpath(os.path.join(bin_dir, lib))
55
- site.addsitedir(path)
56
- sys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length]
57
-
58
- sys.real_prefix = sys.prefix
59
- sys.prefix = base