Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 6 additions & 74 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,80 +22,12 @@ on:
- minor
- major

permissions:
contents: write
pull-requests: write

concurrency:
group: "release"
cancel-in-progress: false

jobs:
release:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v6

- name: "Update Dev Container Index"
run: bash ./scripts/update-data.sh

- name: "Bump to new version"
id: bump
run: |
_version=$(npm --no-git-tag-version version ${{ github.event.inputs.version || 'patch' }})

echo "new_version=$_version" >> $GITHUB_OUTPUT
echo "New version: $_version"

- name: "Create Pull Request"
id: cpr
uses: peter-evans/create-pull-request@v8
with:
token: ${{ secrets.RELEASE_PAT }}
title: "chore(release): bump version to ${{ env.NEW_VERSION }}"
body: "chore(release): bump version to ${{ env.NEW_VERSION }}"
commit-message: "chore(release): bump version to ${{ env.NEW_VERSION }}"
branch: "release-${{ env.NEW_VERSION }}"
delete-branch: true
env:
NEW_VERSION: ${{ steps.bump.outputs.new_version }}

- name: "Auto-merge PR"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}"

- name: "Wait for PR to merge"
if: steps.cpr.outputs.pull-request-number != ''
timeout-minutes: 3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ steps.cpr.outputs.pull-request-number }}
run: |
while true; do
STATE=$(gh pr view "$PR_NUMBER" --json state --template '{{.state}}')
if [ "$STATE" == "MERGED" ]; then
echo "PR merged."
break
fi
if [ "$STATE" == "CLOSED" ]; then
echo "PR closed without merging."
exit 1
fi
echo "State: $STATE. Waiting 3s..."
sleep 3
done

- name: "Release"
if: steps.cpr.outputs.pull-request-number != ''
env:
# https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow#triggering-a-workflow-from-a-workflow
GITHUB_TOKEN: ${{ secrets.RELEASE_PAT }}
NEW_VERSION: ${{ steps.bump.outputs.new_version }}
run: |
gh release create $NEW_VERSION \
--target main \
-t $NEW_VERSION
uses: drehelis/improved-chainsaw/.github/workflows/release.yml@main
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reusable workflow is referenced by branch (@main). For security and supply-chain safety, pin reusable workflow references to an immutable tag or commit SHA so a future change on main cannot unexpectedly alter your release process.

Suggested change
uses: drehelis/improved-chainsaw/.github/workflows/release.yml@main
uses: drehelis/improved-chainsaw/.github/workflows/release.yml@<40-character-commit-sha>

Copilot uses AI. Check for mistakes.
with:
version: ${{ github.event.inputs.version || 'patch' }}
pre_release_command: "bash ./scripts/update-data.sh"
timeout_minutes: 5
secrets: inherit
Comment on lines 26 to +33
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reusable workflow is referenced via @main, which is mutable and increases supply-chain risk. Prefer pinning to a tag or (ideally) a specific commit SHA so the release pipeline can’t change unexpectedly.

Copilot uses AI. Check for mistakes.
Comment on lines 22 to +33
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow no longer sets permissions/concurrency locally. For reusable workflows, the called workflow’s GITHUB_TOKEN permissions are constrained by the caller, and missing concurrency can allow overlapping releases. Consider reintroducing explicit permissions (e.g., contents/pull-requests write if needed) and a release concurrency group here to avoid relying on repo defaults.

Copilot uses AI. Check for mistakes.
114 changes: 30 additions & 84 deletions src/components/layout/ActivityBar.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
<script setup lang="ts">
import type { Section } from "../../types";
import IconPresets from "../ui/icons/IconPresets.vue";
import IconSettings from "../ui/icons/IconSettings.vue";
import IconFeatures from "../ui/icons/IconFeatures.vue";
import IconNetwork from "../ui/icons/IconNetwork.vue";
import IconMounts from "../ui/icons/IconMounts.vue";
import IconAdvanced from "../ui/icons/IconAdvanced.vue";

defineProps<{
activeSection: Section;
Expand All @@ -20,24 +26,15 @@ defineEmits<{
:class="{ active: activeSection === 'presets' }"
title="Presets (Quick Start)"
>
<svg
class="w-6 h-6"
<IconPresets
class="w-6 h-6 transition-colors duration-200"
:class="
activeSection === 'presets'
? 'text-ide-text-bright'
: 'text-ide-text-muted group-hover:text-ide-text'
"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"
/>
</svg>
stroke-width="1.5"
/>
</div>

<div
Expand All @@ -46,130 +43,79 @@ defineEmits<{
:class="{ active: activeSection === 'general' }"
title="General Settings"
>
<svg
class="w-6 h-6"
<IconSettings
class="w-6 h-6 transition-colors duration-200"
:class="
activeSection === 'general'
? 'text-ide-text-bright'
: 'text-ide-text-muted group-hover:text-ide-text'
"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
stroke-width="1.5"
/>
</div>
<div
@click="$emit('update:activeSection', 'features')"
class="activity-item group"
:class="{ active: activeSection === 'features' }"
title="Features"
>
<svg
class="w-6 h-6"
<IconFeatures
class="w-6 h-6 transition-colors duration-200"
:class="
activeSection === 'features'
? 'text-ide-text-bright'
: 'text-ide-text-muted group-hover:text-ide-text'
"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M21 7.5l-9-5.25L3 7.5m18 0l-9 5.25m9-5.25v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-9v9"
/>
</svg>
stroke-width="1.5"
/>
</div>
<div
@click="$emit('update:activeSection', 'ports')"
class="activity-item group"
:class="{ active: activeSection === 'ports' }"
title="Network & Ports"
>
<svg
class="w-6 h-6"
<IconNetwork
class="w-6 h-6 transition-colors duration-200"
:class="
activeSection === 'ports'
? 'text-ide-text-bright'
: 'text-ide-text-muted group-hover:text-ide-text'
"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.963 11.963 0 0112 10.5a11.963 11.963 0 01-7.843-2.918m15.686 0A8.996 8.996 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418"
/>
</svg>
stroke-width="1.5"
/>
</div>
<div
@click="$emit('update:activeSection', 'mounts')"
class="activity-item group"
:class="{ active: activeSection === 'mounts' }"
title="Mounts"
>
<svg
class="w-6 h-6"
<IconMounts
class="w-6 h-6 transition-colors duration-200"
:class="
activeSection === 'mounts'
? 'text-ide-text-bright'
: 'text-ide-text-muted group-hover:text-ide-text'
"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"
/>
</svg>
stroke-width="1.5"
/>
</div>
<div
@click="$emit('update:activeSection', 'advanced')"
class="activity-item group"
:class="{ active: activeSection === 'advanced' }"
title="Advanced & Hooks"
>
<svg
class="w-6 h-6"
<IconAdvanced
class="w-6 h-6 transition-colors duration-200"
:class="
activeSection === 'advanced'
? 'text-ide-text-bright'
: 'text-ide-text-muted group-hover:text-ide-text'
"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"
/>
</svg>
stroke-width="1.5"
/>
</div>
</aside>
</template>
31 changes: 4 additions & 27 deletions src/components/layout/CommandPalette.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script setup lang="ts">
import { ref, computed, watch, useTemplateRef, nextTick } from "vue";
import { useCommandPalette } from "../../composables/useCommandPalette";
import IconSearch from "../ui/icons/IconSearch.vue";
import IconFrown from "../ui/icons/IconFrown.vue";

const {
isOpen,
Expand Down Expand Up @@ -114,19 +116,7 @@ const groupedCommands = computed(() => {
class="flex items-center gap-3 px-4 border-b border-ide-border bg-ide-sidebar"
>
<!-- Search Icon -->
<svg
class="w-4 h-4 text-ide-text-muted shrink-0"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
<IconSearch class="w-4 h-4 text-ide-text-muted shrink-0" />

<input
ref="input"
Expand Down Expand Up @@ -206,24 +196,11 @@ const groupedCommands = computed(() => {
</template>
</template>

<!-- Empty state -->
<div
v-else
class="flex flex-col items-center justify-center py-12 text-ide-text-muted"
>
<svg
class="w-8 h-8 mb-3 opacity-30"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<IconFrown class="w-8 h-8 mb-3 opacity-30" stroke-width="1.5" />
<p class="text-[11px]">
No commands match <em>{{ query }}</em>
</p>
Expand Down
Loading