<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anton Isaiev</title>
    <description>The latest articles on DEV Community by Anton Isaiev (@totoshko88).</description>
    <link>https://dev.to/totoshko88</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2065433%2F66ae70e5-141f-4673-b667-14e1c082dea0.jpg</url>
      <title>DEV Community: Anton Isaiev</title>
      <link>https://dev.to/totoshko88</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/totoshko88"/>
    <language>en</language>
    <item>
      <title>Building a Production-Ready GNOME Extension with Kiro: From CLI to GUI in Record Time</title>
      <dc:creator>Anton Isaiev</dc:creator>
      <pubDate>Mon, 01 Dec 2025 18:49:19 +0000</pubDate>
      <link>https://dev.to/totoshko88/building-a-production-ready-gnome-extension-with-kiro-from-cli-to-gui-in-record-time-1d2n</link>
      <guid>https://dev.to/totoshko88/building-a-production-ready-gnome-extension-with-kiro-from-cli-to-gui-in-record-time-1d2n</guid>
      <description>&lt;p&gt;The Challenge&lt;br&gt;
As a Linux user relying on GlobalProtect VPN, I was tired of managing connections through command-line tools. Every connection meant opening a terminal, typing commands, handling MFA in the browser, and manually checking status. I wanted to build a native GNOME Shell extension that would make VPN management as simple as clicking a system tray icon.&lt;/p&gt;

&lt;p&gt;But GNOME extension development is notoriously complex:&lt;/p&gt;

&lt;p&gt;Strict compliance with extensions.gnome.org review guidelines&lt;br&gt;
Async subprocess management with proper cancellation&lt;br&gt;
Memory leak prevention and resource cleanup&lt;br&gt;
Race condition handling&lt;br&gt;
GJS (GNOME JavaScript) runtime quirks&lt;br&gt;
This wasn't my first GNOME extension, but it was definitely the most complex one I'd attempted.&lt;/p&gt;

&lt;p&gt;Enter Kiro&lt;br&gt;
Kiro transformed what could have been months of development into weeks. Here's how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Intelligent Code Navigation
Working with 1000+ lines of GJS code across multiple modules (extension.js, gpClient.js, statusMonitor.js, indicator.js, errorHandler.js), Kiro helped me maintain architectural consistency. It understood the separation of concerns and suggested improvements that aligned with GNOME best practices.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;// Kiro helped refactor this deprecated pattern:&lt;br&gt;
log('Connection status: ' + status);&lt;/p&gt;

&lt;p&gt;// To the modern approach:&lt;br&gt;
console.info('Connection status:', status);&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Async Operations Done Right
One of the trickiest parts was implementing proper async subprocess operations with Gio.Cancellable. Kiro helped me implement patterns like:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;async connect(portal, gateway = null, username = null) {&lt;br&gt;
    const cancellable = new Gio.Cancellable();&lt;br&gt;
    this._cancellables.add(cancellable);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try {
    const proc = new Gio.Subprocess({
        argv: args,
        flags: Gio.SubprocessFlags.STDOUT_PIPE | 
               Gio.SubprocessFlags.STDERR_PIPE
    });
    proc.init(cancellable);

    const [stdout, stderr] = await proc.communicate_utf8_async(
        null, 
        cancellable
    );
    // Handle result...
} finally {
    this._cancellables.delete(cancellable);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Memory Leak Prevention
GNOME extensions must meticulously clean up resources. Kiro helped me implement proper lifecycle management:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;destroy() {&lt;br&gt;
    // Cancel all operations&lt;br&gt;
    this._cancellables.forEach(c =&amp;gt; c.cancel());&lt;br&gt;
    this._cancellables.clear();&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Remove timeouts
if (this._timeoutId) {
    GLib.Source.remove(this._timeoutId);
    this._timeoutId = null;
}

// Disconnect signals
this._signals.forEach(id =&amp;gt; this.disconnect(id));
this._signals = [];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Race Condition Prevention
Kiro identified potential race conditions when users rapidly clicked connect/disconnect and helped implement operation locks:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;async _connect() {&lt;br&gt;
    if (this._operationInProgress) {&lt;br&gt;
        return; // Prevent concurrent operations&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this._operationInProgress = true;
try {
    await this._gpClient.connect(portal, gateway, username);
} finally {
    this._operationInProgress = false;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Review Guidelines Compliance
The extensions.gnome.org review process is rigorous. Kiro helped me address every requirement:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;✅ Replaced deprecated APIs&lt;br&gt;
✅ Converted PNG icons to SVG&lt;br&gt;
✅ Implemented proper input validation&lt;br&gt;
✅ Added Gio.Cancellable support everywhere&lt;br&gt;
✅ Proper timeout tracking and cleanup&lt;br&gt;
✅ Removed compiled schemas from repo&lt;br&gt;
✅ Fixed cleanup order (reverse of creation)&lt;br&gt;
Result: Passed review on first submission! 🎉&lt;/p&gt;

&lt;p&gt;The Architecture&lt;br&gt;
Kiro helped me maintain a clean, modular architecture:&lt;/p&gt;

&lt;p&gt;┌─────────────────────────────────────────┐&lt;br&gt;
│         Extension (extension.js)        │&lt;br&gt;
│         Lifecycle Management            │&lt;br&gt;
└─────────────────┬───────────────────────┘&lt;br&gt;
                  │&lt;br&gt;
        ┌─────────┴─────────┐&lt;br&gt;
        │                   │&lt;br&gt;
┌───────▼────────┐  ┌──────▼──────────┐&lt;br&gt;
│   Indicator    │  │  StatusMonitor  │&lt;br&gt;
│   (UI Layer)   │  │  (Polling)      │&lt;br&gt;
└───────┬────────┘  └──────┬──────────┘&lt;br&gt;
        │                   │&lt;br&gt;
        └─────────┬─────────┘&lt;br&gt;
                  │&lt;br&gt;
        ┌─────────▼──────────┐&lt;br&gt;
        │   GlobalProtect    │&lt;br&gt;
        │   Client           │&lt;br&gt;
        │   (CLI Wrapper)    │&lt;br&gt;
        └────────────────────┘&lt;br&gt;
Key Features Implemented&lt;br&gt;
🔒 Connect/Disconnect with MFA support&lt;br&gt;
📊 Real-time status monitoring&lt;br&gt;
🌐 Gateway selection and switching&lt;br&gt;
🔄 Auto-disconnect on logout&lt;br&gt;
🎨 Custom SVG icons for all states&lt;br&gt;
🔔 Smart notifications with throttling&lt;br&gt;
⚙️ Interactive settings dialogs&lt;br&gt;
🔍 Advanced operations (HIP, logs, network rediscovery)&lt;br&gt;
🛡️ Comprehensive error handling with data sanitization&lt;br&gt;
Testing with Kiro&lt;br&gt;
Kiro helped me implement comprehensive testing:&lt;/p&gt;

&lt;p&gt;Property-Based Tests (using fast-check):&lt;/p&gt;

&lt;p&gt;fc.assert(&lt;br&gt;
    fc.property(fc.string(), async (input) =&amp;gt; {&lt;br&gt;
        const sanitized = ErrorHandler.sanitize(input);&lt;br&gt;
        // Ensure no sensitive data leaks&lt;br&gt;
        expect(sanitized).not.toContain('password');&lt;br&gt;
        expect(sanitized).not.toContain('token');&lt;br&gt;
    }),&lt;br&gt;
    { numRuns: 100 }&lt;br&gt;
);&lt;br&gt;
Unit Tests (using Jasmine):&lt;/p&gt;

&lt;p&gt;describe('GlobalProtectClient', () =&amp;gt; {&lt;br&gt;
    it('should handle connection timeout', async () =&amp;gt; {&lt;br&gt;
        const client = new GlobalProtectClient();&lt;br&gt;
        await expectAsync(&lt;br&gt;
            client.connect('invalid-portal')&lt;br&gt;
        ).toBeRejectedWithError(/timeout/i);&lt;br&gt;
    });&lt;br&gt;
});&lt;br&gt;
The Results&lt;br&gt;
✅ Published on extensions.gnome.org&lt;br&gt;
✅ 100% Review Compliance&lt;br&gt;
✅ Zero Memory Leaks&lt;br&gt;
✅ Comprehensive Test Coverage&lt;br&gt;
✅ 1.3k+ lines of production code&lt;br&gt;
✅ Compatible with GNOME Shell 45-49&lt;br&gt;
What Changed in My Development Approach&lt;br&gt;
Before Kiro:&lt;/p&gt;

&lt;p&gt;Manual code review for patterns&lt;br&gt;
Trial and error with async operations&lt;br&gt;
Debugging memory leaks after the fact&lt;br&gt;
Multiple review submission attempts&lt;br&gt;
With Kiro:&lt;/p&gt;

&lt;p&gt;AI-assisted best practices from the start&lt;br&gt;
Proper patterns implemented first time&lt;br&gt;
Proactive memory management&lt;br&gt;
First-submission approval&lt;br&gt;
Kiro didn't just help me write code faster - it helped me write better code from the beginning. The AI understands context, suggests improvements, and catches issues before they become problems.&lt;/p&gt;

&lt;p&gt;Try It Yourself&lt;br&gt;
The extension is open source and available now:&lt;/p&gt;

&lt;p&gt;🔗 GitHub: &lt;a href="https://github.com/totoshko88/gp-gnome" rel="noopener noreferrer"&gt;https://github.com/totoshko88/gp-gnome&lt;/a&gt; 📦 Install: gnome-extensions install &lt;a href="mailto:gp-gnome@totoshko88.github.io.zip"&gt;gp-gnome@totoshko88.github.io.zip&lt;/a&gt; ⭐ GNOME Extensions: &lt;a href="https://extensions.gnome.org/extension/8899/gp-gnome/" rel="noopener noreferrer"&gt;https://extensions.gnome.org/extension/8899/gp-gnome/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Conclusion&lt;br&gt;
Building a production-ready GNOME extension is challenging, but with Kiro as a development partner, it became manageable and even enjoyable. The combination of intelligent code suggestions, architectural guidance, and best practice enforcement made the difference between a hobby project and a professional, publishable extension.&lt;/p&gt;

&lt;p&gt;If you're working on complex projects - especially those with strict compliance requirements - Kiro is a game-changer.&lt;/p&gt;

&lt;p&gt;What's your experience with AI-assisted development? Share in the comments!&lt;/p&gt;

&lt;h1&gt;
  
  
  kiro #gnome #linux #opensource #javascript #gjs #vpn #devtools
&lt;/h1&gt;

</description>
      <category>kiro</category>
      <category>gnome</category>
      <category>linux</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
