-
Notifications
You must be signed in to change notification settings - Fork 19
feat: wire kortex-cli init and add CLI logging #1231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,9 +23,11 @@ import { inject, injectable, preDestroy } from 'inversify'; | |
| import { parse as parseYAML } from 'yaml'; | ||
|
|
||
| import { IPCHandle } from '/@/plugin/api.js'; | ||
| import { CliToolRegistry } from '/@/plugin/cli-tool-registry.js'; | ||
| import { Exec } from '/@/plugin/util/exec.js'; | ||
| import type { | ||
| AgentWorkspaceConfiguration, | ||
| AgentWorkspaceCreateOptions, | ||
| AgentWorkspaceId, | ||
| AgentWorkspaceSummary, | ||
| } from '/@api/agent-workspace-info.js'; | ||
|
|
@@ -43,11 +45,53 @@ export class AgentWorkspaceManager implements Disposable { | |
| private readonly ipcHandle: IPCHandle, | ||
| @inject(Exec) | ||
| private readonly exec: Exec, | ||
| @inject(CliToolRegistry) | ||
| private readonly cliToolRegistry: CliToolRegistry, | ||
| ) {} | ||
|
|
||
| private async execKortex<T>(args: string[]): Promise<T> { | ||
| const result = await this.exec.exec('kortex-cli', ['workspace', ...args, '--output', 'json']); | ||
| return JSON.parse(result.stdout) as T; | ||
| private getCliPath(): string { | ||
| const tool = this.cliToolRegistry.getCliToolInfos().find(t => t.name === 'kortex'); | ||
| if (tool?.path) { | ||
| return tool.path; | ||
| } | ||
| return 'kortex-cli'; | ||
| } | ||
|
|
||
| private async execKortex<T>(args: string[], options?: { cwd?: string }): Promise<T> { | ||
| const cliPath = this.getCliPath(); | ||
| const fullArgs = ['workspace', ...args, '--output', 'json']; | ||
| console.log(`Executing: ${cliPath} ${fullArgs.join(' ')}`); | ||
| try { | ||
| const result = await this.exec.exec(cliPath, fullArgs, options); | ||
| return JSON.parse(result.stdout) as T; | ||
| } catch (err: unknown) { | ||
| const message = err instanceof Error ? err.message : String(err); | ||
| console.log(`kortex-cli failed: ${cliPath} ${fullArgs.join(' ')} — ${message}`); | ||
| throw err; | ||
| } | ||
| } | ||
|
|
||
| async create(options: AgentWorkspaceCreateOptions): Promise<AgentWorkspaceId> { | ||
| const cliPath = this.getCliPath(); | ||
| const runtime = options.runtime ?? 'podman'; | ||
| const args = ['init', options.sourcePath, '--runtime', runtime, '--agent', options.agent, '--output', 'json']; | ||
| if (options.name) { | ||
| args.push('--name', options.name); | ||
| } | ||
| if (options.project) { | ||
| args.push('--project', options.project); | ||
| } | ||
| console.log(`Executing: ${cliPath} ${args.join(' ')}`); | ||
| try { | ||
| const result = await this.exec.exec(cliPath, args); | ||
| const workspaceId = JSON.parse(result.stdout) as AgentWorkspaceId; | ||
| this.apiSender.send('agent-workspace-update'); | ||
| return workspaceId; | ||
| } catch (err: unknown) { | ||
| const message = err instanceof Error ? err.message : String(err); | ||
| console.log(`kortex-cli failed: ${cliPath} ${args.join(' ')} — ${message}`); | ||
| throw err; | ||
| } | ||
| } | ||
|
Comment on lines
+74
to
95
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Track This shells out to an external CLI and can easily outlive the form-local spinner, but it never creates a task or publishes status the rest of the app can observe. Mirroring the other main-process CLI flows here would give users durable progress and failure reporting even if they navigate away. As per coding guidelines, "Long-running operations should use 🤖 Prompt for AI Agents |
||
|
|
||
| async list(): Promise<AgentWorkspaceSummary[]> { | ||
|
|
@@ -84,6 +128,13 @@ export class AgentWorkspaceManager implements Disposable { | |
| } | ||
|
|
||
| init(): void { | ||
| this.ipcHandle( | ||
| 'agent-workspace:create', | ||
| async (_listener: unknown, options: AgentWorkspaceCreateOptions): Promise<AgentWorkspaceId> => { | ||
| return this.create(options); | ||
| }, | ||
| ); | ||
|
|
||
| this.ipcHandle('agent-workspace:list', async (): Promise<AgentWorkspaceSummary[]> => { | ||
| return this.list(); | ||
| }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -112,8 +112,11 @@ function cancel(): void { | |
| handleNavigation({ page: NavigationPage.AGENT_WORKSPACES }); | ||
| } | ||
|
|
||
| function startWorkspace(): void { | ||
| if (!sessionName.trim()) return; | ||
| let creating = $state(false); | ||
| let error = $state(''); | ||
|
|
||
| async function startWorkspace(): Promise<void> { | ||
| if (!sessionName.trim() || !workingDir.trim() || !selectedAgent) return; | ||
|
|
||
| const config = { | ||
| name: sessionName, | ||
|
|
@@ -126,6 +129,21 @@ function startWorkspace(): void { | |
| mcpServers: selectedMcpIds, | ||
| }; | ||
| console.log('Starting workspace with config:', config); | ||
|
|
||
| creating = true; | ||
| error = ''; | ||
| try { | ||
| await window.createAgentWorkspace({ | ||
| sourcePath: workingDir, | ||
| agent: selectedAgent, | ||
| name: sessionName, | ||
| }); | ||
|
Comment on lines
+136
to
+140
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Forward This call only sends 🤖 Prompt for AI Agents |
||
| handleNavigation({ page: NavigationPage.AGENT_WORKSPACES }); | ||
| } catch (err: unknown) { | ||
| error = err instanceof Error ? err.message : String(err); | ||
| } finally { | ||
| creating = false; | ||
| } | ||
| } | ||
| </script> | ||
|
|
||
|
|
@@ -264,6 +282,10 @@ function startWorkspace(): void { | |
| {/if} | ||
| </section> | ||
|
|
||
| {#if error} | ||
| <div class="text-sm text-red-400 bg-red-900/20 rounded-lg p-3">{error}</div> | ||
| {/if} | ||
|
|
||
| <!-- Footer actions --> | ||
| <div class="flex items-center justify-between pt-4 border-t border-[var(--pd-content-card-border)]"> | ||
| <div class="flex items-center gap-3 text-sm text-[var(--pd-content-card-text)] opacity-70"> | ||
|
|
@@ -272,7 +294,9 @@ function startWorkspace(): void { | |
| </div> | ||
| <div class="flex gap-3"> | ||
| <Button onclick={cancel}>Cancel</Button> | ||
| <Button disabled={!sessionName.trim()} onclick={startWorkspace}>Start Workspace</Button> | ||
| <Button disabled={!sessionName.trim() || !workingDir.trim() || !selectedAgent || creating} onclick={startWorkspace}> | ||
| {creating ? 'Creating...' : 'Start Workspace'} | ||
| </Button> | ||
| </div> | ||
| </div> | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: kortex-hub/kortex
Length of output: 138
🏁 Script executed:
Repository: kortex-hub/kortex
Length of output: 1701
Rename imported
Proxytype to avoid lint-blocking global shadowing.The
Proxyimport at line 27 shadows the globalProxyobject, triggeringlint/suspicious/noShadowRestrictedNamesand blocking CI.Proposed fix
🧰 Tools
🪛 Biome (2.4.9)
[error] 27-27: Do not shadow the global "Proxy" property.
(lint/suspicious/noShadowRestrictedNames)
🤖 Prompt for AI Agents