Skip to content

Commit d0e666d

Browse files
Dchuong03claude
andcommitted
feat: add chore TaskType + CI deploy to GHCR
- Add 'chore' to TaskType union, governance config, and frontend badges - Add defensive fallback in resolveGovernance() for unknown task types - Fix missing 'chore' in database.ts inferTaskTypeFromContent() - New deploy workflow: build Docker images and push to ghcr.io on push to main - Update docker-compose to pull pre-built images from GHCR Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 478d3a6 commit d0e666d

6 files changed

Lines changed: 84 additions & 10 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Deploy
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- 'packages/**'
8+
- 'docker/**'
9+
- 'pnpm-lock.yaml'
10+
11+
jobs:
12+
build-push:
13+
name: Build & Push ${{ matrix.service }}
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
packages: write
18+
strategy:
19+
matrix:
20+
service: [api-server, mcp-server]
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- name: Log in to GHCR
26+
uses: docker/login-action@v3
27+
with:
28+
registry: ghcr.io
29+
username: ${{ github.actor }}
30+
password: ${{ secrets.GITHUB_TOKEN }}
31+
32+
- name: Extract version
33+
id: version
34+
run: echo "version=$(node -p 'require(\"./package.json\").version')" >> "$GITHUB_OUTPUT"
35+
36+
- name: Docker meta
37+
id: meta
38+
uses: docker/metadata-action@v5
39+
with:
40+
images: ghcr.io/junixlabs/sidstack-${{ matrix.service }}
41+
tags: |
42+
type=raw,value=latest
43+
type=sha,prefix=sha-,format=short
44+
type=raw,value=v${{ steps.version.outputs.version }}
45+
46+
- name: Build & push
47+
uses: docker/build-push-action@v6
48+
with:
49+
context: .
50+
file: docker/${{ matrix.service }}/Dockerfile
51+
push: true
52+
tags: ${{ steps.meta.outputs.tags }}
53+
labels: ${{ steps.meta.outputs.labels }}

docker/deploy/docker-compose.yml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33

44
services:
55
api-server:
6-
build:
7-
context: ../../
8-
dockerfile: docker/api-server/Dockerfile
6+
image: ghcr.io/junixlabs/sidstack-api-server:latest
97
container_name: sidstack-api
108
ports:
119
- "127.0.0.1:19432:19432"
@@ -29,9 +27,7 @@ services:
2927
start_period: 10s
3028

3129
mcp-server:
32-
build:
33-
context: ../../
34-
dockerfile: docker/mcp-server/Dockerfile
30+
image: ghcr.io/junixlabs/sidstack-mcp-server:latest
3531
container_name: sidstack-mcp
3632
ports:
3733
- "127.0.0.1:19433:19433"

packages/shared/src/database.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4085,7 +4085,7 @@ export class SidStackDB {
40854085
const prefixMatch = title.match(/^\[(\w+)\]/);
40864086
if (prefixMatch) {
40874087
const prefix = prefixMatch[1].toLowerCase();
4088-
const validTypes: TaskType[] = ['feature', 'bugfix', 'refactor', 'test', 'docs', 'infra', 'security', 'perf', 'debt', 'spike'];
4088+
const validTypes: TaskType[] = ['feature', 'bugfix', 'refactor', 'test', 'docs', 'infra', 'security', 'perf', 'debt', 'spike', 'chore'];
40894089
if (validTypes.includes(prefix as TaskType)) {
40904090
return prefix as TaskType;
40914091
}

packages/shared/src/governance.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ export type TaskType =
1919
| 'security' // Security-related
2020
| 'perf' // Performance optimization
2121
| 'debt' // Technical debt cleanup
22-
| 'spike'; // Research/investigation
22+
| 'spike' // Research/investigation
23+
| 'chore'; // Routine maintenance
2324

2425
export const TASK_TYPES: TaskType[] = [
2526
'feature', 'bugfix', 'refactor', 'test', 'docs',
26-
'infra', 'security', 'perf', 'debt', 'spike'
27+
'infra', 'security', 'perf', 'debt', 'spike', 'chore'
2728
];
2829

2930
export function isValidTaskType(type: string): type is TaskType {
@@ -168,6 +169,13 @@ export const TASK_TYPE_GOVERNANCE: Record<TaskType, GovernanceConfig> = {
168169
requiredCriteria: false,
169170
reviewRequired: false,
170171
},
172+
chore: {
173+
principles: ['task-management'],
174+
skills: [],
175+
qualityGates: [],
176+
requiredCriteria: false,
177+
reviewRequired: false,
178+
},
171179
};
172180

173181
/**
@@ -184,6 +192,7 @@ export const MIN_PROGRESS_UPDATES: Record<TaskType, number> = {
184192
perf: 3, // Profile, optimize, verify
185193
debt: 2, // Start, complete
186194
spike: 1, // Complete with findings
195+
chore: 1, // Complete
187196
};
188197

189198
// ============================================================================
@@ -202,6 +211,15 @@ export interface ModuleGovernance {
202211
};
203212
}
204213

214+
const FALLBACK_GOVERNANCE: TaskGovernance = {
215+
principles: ['task-management'],
216+
skills: [],
217+
patterns: [],
218+
qualityGates: [],
219+
requiredCriteria: false,
220+
reviewRequired: false,
221+
};
222+
205223
/**
206224
* Resolve governance for a task based on task type and optional module
207225
*/
@@ -211,6 +229,11 @@ export function resolveGovernance(
211229
): TaskGovernance {
212230
const config = TASK_TYPE_GOVERNANCE[taskType];
213231

232+
// Defensive fallback for unknown task types (runtime safety for untyped callers)
233+
if (!config) {
234+
return FALLBACK_GOVERNANCE;
235+
}
236+
214237
// Build quality gates with commands
215238
const qualityGates: QualityGate[] = config.qualityGates.map(gateId => ({
216239
id: gateId,

src/components/tasks/badges/TaskTypeBadge.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
Zap,
1010
Wrench,
1111
Microscope,
12+
ClipboardList,
1213
} from "lucide-react";
1314
import { type ReactNode } from "react";
1415

@@ -31,6 +32,7 @@ const TASK_TYPE_CONFIG: Record<TaskType, { bgVar: string; textVar: string; icon:
3132
perf: { bgVar: "var(--task-perf-bg)", textVar: "var(--task-perf)", icon: <Zap className="w-3 h-3" /> },
3233
debt: { bgVar: "var(--task-debt-bg)", textVar: "var(--task-debt)", icon: <Wrench className="w-3 h-3" /> },
3334
spike: { bgVar: "var(--task-spike-bg)", textVar: "var(--task-spike)", icon: <Microscope className="w-3 h-3" /> },
35+
chore: { bgVar: "var(--task-infra-bg)", textVar: "var(--task-infra)", icon: <ClipboardList className="w-3 h-3" /> },
3436
};
3537

3638
export function TaskTypeBadge({ taskType, showIcon = false }: TaskTypeBadgeProps) {

src/stores/taskStore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { create } from "zustand";
1313

1414
export type TaskStatus = "pending" | "review" | "in_progress" | "completed" | "blocked" | "failed" | "cancelled";
1515
export type TaskPriority = "low" | "medium" | "high";
16-
export type TaskType = "feature" | "bugfix" | "refactor" | "test" | "docs" | "infra" | "security" | "perf" | "debt" | "spike";
16+
export type TaskType = "feature" | "bugfix" | "refactor" | "test" | "docs" | "infra" | "security" | "perf" | "debt" | "spike" | "chore";
1717
export type ViewMode = "list" | "tree" | "kanban" | "timeline";
1818

1919
export interface AcceptanceCriterion {

0 commit comments

Comments
 (0)