fifony 0.1.26 → 0.1.27-next.84df008
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.
- package/README.md +152 -129
- package/app/dist/assets/{KeyboardShortcutsHelp-lTNj9GiT.js → KeyboardShortcutsHelp-By0KcDhZ.js} +1 -1
- package/app/dist/assets/OnboardingWizard-5cz7Onsu.js +1 -0
- package/app/dist/assets/{analytics.lazy-C42PFRzr.js → analytics.lazy-ArFwnOEn.js} +1 -1
- package/app/dist/assets/{createLucideIcon-BWC-guQt.js → createLucideIcon-DgMTp0yx.js} +1 -1
- package/app/dist/assets/index-59O8esMr.js +45 -0
- package/app/dist/assets/{index-Qr2OPvRO.css → index-DuBwUsuf.css} +1 -1
- package/app/dist/assets/vendor-D-IqxHHu.js +9 -0
- package/app/dist/dinofffaur.webp +0 -0
- package/app/dist/index.html +4 -4
- package/app/dist/service-worker.js +1 -1
- package/dist/agent/run-local.js +57 -144
- package/dist/agent-KMXNVDRO.js +74 -0
- package/dist/chunk-FJR4ALEN.js +847 -0
- package/dist/{chunk-2F3Q2MAG.js → chunk-HSGUPFTV.js} +1224 -611
- package/dist/chunk-O5AEQXUV.js +311 -0
- package/dist/chunk-OONOOWNC.js +123 -0
- package/dist/{chunk-NFHVAIPW.js → chunk-UYCDOH6S.js} +380 -795
- package/dist/chunk-XENKNHFS.js +295 -0
- package/dist/cli.js +6 -4
- package/dist/issue-runner-JJAFMHKV.js +15 -0
- package/dist/{issue-state-machine-OWABY5S2.js → issue-state-machine-ACMUJSXC.js} +5 -3
- package/dist/issues-VDFXBK3N.js +40 -0
- package/dist/mcp/server.js +23 -121
- package/dist/queue-workers-U47CVPTO.js +23 -0
- package/dist/scheduler-MEXEDV4M.js +21 -0
- package/dist/{store-WN47MDT5.js → store-AG6LLYJ7.js} +7 -5
- package/dist/workspace-474CCKTW.js +44 -0
- package/package.json +6 -6
- package/app/dist/assets/OnboardingWizard-B6LlJR9B.js +0 -1
- package/app/dist/assets/index-fVSxs9d5.js +0 -43
- package/app/dist/assets/vendor-BTlTWMUF.js +0 -9
- package/dist/chunk-AMOGDOM7.js +0 -796
- package/dist/chunk-IA7IMQ5F.js +0 -91
- package/dist/issue-runner-DA4IDLKX.js +0 -13
- package/dist/queue-workers-JIH5ZMNQ.js +0 -20
package/README.md
CHANGED
|
@@ -1,60 +1,128 @@
|
|
|
1
|
-
<
|
|
1
|
+
<p>
|
|
2
|
+
<img src="app/public/dinofffaur.png" alt="fifony mascot" width="120" align="left" />
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
## fifony
|
|
4
6
|
|
|
5
7
|
**AI agents that actually ship code. You just watch.**
|
|
6
8
|
|
|
7
|
-
Point at a repo. Open the dashboard. AI plans, builds, and reviews — you approve.
|
|
9
|
+
Point at a repo. Open the dashboard. AI plans, builds, and reviews — you approve and merge.
|
|
8
10
|
|
|
9
|
-
[](LICENSE)
|
|
10
|
-
[]()
|
|
11
|
+
[](LICENSE) []()
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
<div style="clear:both"></div>
|
|
13
14
|
|
|
14
15
|
---
|
|
15
16
|
|
|
16
17
|
## Quick Start
|
|
17
18
|
|
|
18
19
|
```bash
|
|
19
|
-
npx -y fifony
|
|
20
|
+
npx -y fifony
|
|
20
21
|
```
|
|
21
22
|
|
|
22
|
-
Open **http://localhost:
|
|
23
|
+
Open **http://localhost:4000**. The first run launches the onboarding wizard — it detects your CLIs, scans your project, and configures everything in six steps. State lives in `.fifony/`. No accounts, no cloud, no external database.
|
|
24
|
+
|
|
25
|
+
<div align="center">
|
|
26
|
+
<img src="docs/ss-01.webp" alt="Onboarding wizard" width="720" />
|
|
27
|
+
</div>
|
|
23
28
|
|
|
24
29
|
---
|
|
25
30
|
|
|
26
31
|
## How It Works
|
|
27
32
|
|
|
28
|
-
fifony
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
Plan Execute Review
|
|
32
|
-
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
33
|
-
│ Claude │─▶│ Codex │─▶│ Claude │
|
|
34
|
-
│ Opus 4.5 │ │ │ │ Sonnet 4.5 │
|
|
35
|
-
│ effort: high │ │ effort: med │ │ effort: med │
|
|
36
|
-
└──────────────┘ └──────────────┘ └──────────────┘
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
You set the provider, model, and reasoning effort for each stage. Claude plans, Codex executes, Claude reviews — or any combination you prefer. Configure it in the Settings UI or drop a `WORKFLOW.md` in your project root.
|
|
33
|
+
fifony auto-detects your installed CLI tools (Claude, Codex, Gemini) and routes each pipeline stage to the best available provider. Configure per-stage provider, model, and reasoning effort in the Settings UI or drop a `WORKFLOW.md` in your project root.
|
|
40
34
|
|
|
41
35
|
### Issue Lifecycle
|
|
42
36
|
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
```mermaid
|
|
38
|
+
stateDiagram-v2
|
|
39
|
+
direction LR
|
|
40
|
+
|
|
41
|
+
classDef planning fill:#38bdf8,color:#fff,stroke:#0ea5e9,stroke-width:2px
|
|
42
|
+
classDef approval fill:#fbbf24,color:#000,stroke:#f59e0b,stroke-width:2px
|
|
43
|
+
classDef queued fill:#a78bfa,color:#fff,stroke:#8b5cf6,stroke-width:2px
|
|
44
|
+
classDef running fill:#818cf8,color:#fff,stroke:#6366f1,stroke-width:2px
|
|
45
|
+
classDef review fill:#f59e0b,color:#fff,stroke:#d97706,stroke-width:2px
|
|
46
|
+
classDef done fill:#34d399,color:#fff,stroke:#10b981,stroke-width:2px
|
|
47
|
+
classDef merged fill:#22c55e,color:#fff,stroke:#16a34a,stroke-width:3px
|
|
48
|
+
classDef blocked fill:#f87171,color:#fff,stroke:#ef4444,stroke-width:2px
|
|
49
|
+
classDef cancelled fill:#9ca3af,color:#fff,stroke:#6b7280,stroke-width:2px
|
|
50
|
+
|
|
51
|
+
[*] --> Planning
|
|
52
|
+
Planning --> PendingApproval: PLANNED
|
|
53
|
+
PendingApproval --> Queued: QUEUE
|
|
54
|
+
PendingApproval --> Planning: REPLAN
|
|
55
|
+
Queued --> Running: RUN
|
|
56
|
+
Running --> Reviewing: REVIEW
|
|
57
|
+
Running --> Queued: REQUEUE
|
|
58
|
+
Running --> Blocked: BLOCK
|
|
59
|
+
Reviewing --> PendingDecision: REVIEWED
|
|
60
|
+
Reviewing --> Queued: REQUEUE
|
|
61
|
+
Reviewing --> Blocked: BLOCK
|
|
62
|
+
PendingDecision --> Approved: APPROVE
|
|
63
|
+
PendingDecision --> Queued: REQUEUE (rework)
|
|
64
|
+
PendingDecision --> Planning: REPLAN
|
|
65
|
+
Approved --> Merged: MERGE
|
|
66
|
+
Approved --> Planning: REOPEN
|
|
67
|
+
|
|
68
|
+
Blocked --> Queued: UNBLOCK
|
|
69
|
+
Blocked --> Planning: REPLAN
|
|
70
|
+
|
|
71
|
+
Merged --> Planning: REOPEN
|
|
72
|
+
Merged --> Archived: ARCHIVE
|
|
73
|
+
|
|
74
|
+
Planning --> Cancelled: CANCEL
|
|
75
|
+
PendingApproval --> Cancelled: CANCEL
|
|
76
|
+
PendingDecision --> Cancelled: CANCEL
|
|
77
|
+
Blocked --> Cancelled: CANCEL
|
|
78
|
+
Cancelled --> Planning: REOPEN
|
|
79
|
+
Cancelled --> Archived: ARCHIVE
|
|
80
|
+
|
|
81
|
+
Archived --> [*]
|
|
82
|
+
Merged --> [*]
|
|
83
|
+
Cancelled --> [*]
|
|
84
|
+
|
|
85
|
+
class Planning planning
|
|
86
|
+
class PendingApproval,PendingDecision approval
|
|
87
|
+
class Queued queued
|
|
88
|
+
class Running running
|
|
89
|
+
class Reviewing review
|
|
90
|
+
class Approved done
|
|
91
|
+
class Merged merged
|
|
92
|
+
class Blocked blocked
|
|
93
|
+
class Cancelled cancelled
|
|
94
|
+
class Archived cancelled
|
|
47
95
|
```
|
|
48
96
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
97
|
+
| Step | Who | State | What happens |
|
|
98
|
+
|------|-----|-------|-------------|
|
|
99
|
+
| **Create** | You | → Planning | Describe what you want. Hit **Enhance** — AI rewrites your spec with acceptance criteria and edge cases. |
|
|
100
|
+
| **Plan** | AI | Planning | The planner generates a structured execution plan: phases, steps, target files, complexity, risks. |
|
|
101
|
+
| **Approve plan** | You | PendingApproval → Queued | You review the plan. Optionally refine with AI chat before approving. |
|
|
102
|
+
| **Execute** | AI | Running | Agents run in an isolated git worktree. Live output streams to the dashboard. |
|
|
103
|
+
| **Review** | AI | Reviewing | The reviewer inspects the diff — approves, requests rework, or blocks. |
|
|
104
|
+
| **Decide** | You | PendingDecision → Approved | You confirm the review. Approve to merge, request rework, or replan. |
|
|
105
|
+
| **Merge** | You | Approved → Merged | Merge the worktree into your project. Analytics capture lines added/removed. |
|
|
106
|
+
| **Archive** | You | Merged/Cancelled → Archived | Soft-delete: issue disappears from all views but stays in the database. |
|
|
107
|
+
|
|
108
|
+
**Retry operations** are semantically distinct — each has its own command, FSM path, and prompt context:
|
|
109
|
+
|
|
110
|
+
| Retry | Command | What happens |
|
|
111
|
+
|-------|---------|-------------|
|
|
112
|
+
| **Replan** | `replanIssueCommand` | Archives current plan, increments plan version, resets execution/review counters, generates fresh plan. |
|
|
113
|
+
| **Re-execute** | `retryExecutionCommand` | Retries from Blocked. Prior failure insights analyzed and injected into prompt — agent avoids repeating the same mistake. |
|
|
114
|
+
| **Rework** | `requestReworkCommand` | Reviewer requested changes. Feedback archived as structured failure insight, issue re-queued for another execution attempt. |
|
|
55
115
|
|
|
56
116
|
Agents run as detached child processes, tracked by PID. If the server restarts mid-run, fifony recovers on the next boot.
|
|
57
117
|
|
|
118
|
+
<div align="center">
|
|
119
|
+
<img src="docs/ss-02.webp" alt="Create issue with Enhance" width="720" />
|
|
120
|
+
<br><sub>Create an issue and hit Enhance — AI writes a full spec</sub>
|
|
121
|
+
<br><br>
|
|
122
|
+
<img src="docs/ss-03.webp" alt="Plan review and approve" width="720" />
|
|
123
|
+
<br><sub>Review the AI-generated plan, refine it, then approve to start execution</sub>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
58
126
|
---
|
|
59
127
|
|
|
60
128
|
## Onboarding Wizard
|
|
@@ -63,7 +131,7 @@ The first run walks you through six steps:
|
|
|
63
131
|
|
|
64
132
|
| Step | What happens |
|
|
65
133
|
|------|-------------|
|
|
66
|
-
| CLI Detection | Finds `claude`, `codex`, `git`, `node`, `docker`, and other tools on your system |
|
|
134
|
+
| CLI Detection | Finds `claude`, `codex`, `gemini`, `git`, `node`, `docker`, and other tools on your system |
|
|
67
135
|
| Project Scan | Detects language, stack, and build system — 18+ ecosystems supported |
|
|
68
136
|
| AI Analysis | Uses the detected CLI to extract domain context from your codebase |
|
|
69
137
|
| Domains | 21 options across Technical / Industry / Role, pre-selected by the AI |
|
|
@@ -72,86 +140,83 @@ The first run walks you through six steps:
|
|
|
72
140
|
|
|
73
141
|
Settings are saved progressively and can be re-run from Settings at any time.
|
|
74
142
|
|
|
75
|
-
Supported build files include: `package.json`, `Cargo.toml`, `pyproject.toml`, `go.mod`, `build.gradle`, `Gemfile`, `mix.exs`, `pubspec.yaml`, `CMakeLists.txt`, `composer.json`, `Package.swift`, `deno.json`, `pom.xml`, `Dockerfile`, and more.
|
|
76
|
-
|
|
77
143
|
---
|
|
78
144
|
|
|
79
145
|
## Dashboard
|
|
80
146
|
|
|
81
147
|
| Route | What you see |
|
|
82
148
|
|-------|-------------|
|
|
83
|
-
| `/kanban` | Drag-and-drop board
|
|
84
|
-
| `/issues` | Searchable list with multi-state filters, sort options, and capability filters.
|
|
149
|
+
| `/kanban` | Drag-and-drop board with 5 columns: Planning, In Progress, Reviewing, Blocked, Done. |
|
|
150
|
+
| `/issues` | Searchable list with multi-state filters, sort options, and capability filters. |
|
|
85
151
|
| `/agents` | Live cockpit: worker slots, queue depth, real-time log tail, token sparklines per agent. |
|
|
86
152
|
| `/analytics` | Token usage trends, daily and weekly rollups, top issues by cost, per-model breakdown. |
|
|
87
153
|
| `/settings` | General, Workflow pipeline config, Notifications, Providers. |
|
|
88
154
|
|
|
89
155
|
The **Issue Detail Drawer** shows the full plan (phases and steps), all execution sessions, the workspace diff, and a per-phase token breakdown — Plan / Execute / Review — with input and output counts per model.
|
|
90
156
|
|
|
157
|
+
<div align="center">
|
|
158
|
+
<img src="docs/ss-04.webp" alt="Agents cockpit" width="720" />
|
|
159
|
+
<br><sub>Agents cockpit — live output, worker slots, token usage</sub>
|
|
160
|
+
<br><br>
|
|
161
|
+
<img src="docs/ss-05.webp" alt="Analytics dashboard" width="720" />
|
|
162
|
+
<br><sub>Analytics — token trends, code churn, engineering KPIs, model breakdown</sub>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
91
165
|
### PWA
|
|
92
166
|
|
|
93
167
|
Install as a desktop app. Works offline. Desktop notifications when issues change state. Service worker with stale-while-revalidate caching.
|
|
94
168
|
|
|
95
169
|
---
|
|
96
170
|
|
|
97
|
-
##
|
|
171
|
+
## Agents, Skills & Reference Repositories
|
|
98
172
|
|
|
99
|
-
fifony
|
|
173
|
+
fifony pulls agents and skills from three open-source reference repositories during onboarding:
|
|
100
174
|
|
|
101
|
-
|
|
|
102
|
-
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
|
|
|
106
|
-
| Security Engineer | OWASP, threat modeling, secure code review |
|
|
107
|
-
| DevOps Automator | CI/CD, Docker, Kubernetes, cloud infrastructure |
|
|
108
|
-
| Mobile App Builder | iOS, Android, React Native, Flutter |
|
|
109
|
-
| AI Engineer | ML models, LLM integration, data pipelines |
|
|
110
|
-
| UI Designer | Visual design, component libraries, design systems |
|
|
111
|
-
| UX Architect | UX patterns, accessibility, information architecture |
|
|
112
|
-
| Code Reviewer | Code quality, best practices, constructive feedback |
|
|
113
|
-
| Technical Writer | Docs, READMEs, API references, tutorials |
|
|
114
|
-
| SRE | Reliability, observability, incident response |
|
|
115
|
-
| Data Engineer | ETL, data warehousing, analytics infrastructure |
|
|
116
|
-
| Software Architect | System design, DDD, architectural patterns |
|
|
117
|
-
| Game Designer | Game mechanics, level design, cross-engine |
|
|
175
|
+
| Repository | What it provides |
|
|
176
|
+
|------------|-----------------|
|
|
177
|
+
| **[LerianStudio/ring](https://github.com/LerianStudio/ring)** | 80+ specialist agents, skills, engineering standards, review commands, and prompt libraries for full-stack development. |
|
|
178
|
+
| **[msitarzewski/agency-agents](https://github.com/msitarzewski/agency-agents)** | Focused agent set for frontend, backend, QA, and review roles. |
|
|
179
|
+
| **[pbakaus/impeccable](https://github.com/pbakaus/impeccable)** | Frontend polish skills — design system enforcement, accessibility audits, and visual quality workflows. |
|
|
118
180
|
|
|
119
|
-
|
|
181
|
+
Repositories are cloned to `~/.fifony/repositories/` and synced on demand. During onboarding, fifony scans them and recommends agents/skills matching your project's domain. You pick what to install.
|
|
120
182
|
|
|
121
|
-
Agents install to `.claude/agents/` and `.codex/agents
|
|
183
|
+
Agents install to `.claude/agents/` and `.codex/agents/`. Skills load from `SKILL.md` files in `.claude/skills/` or `.codex/skills/`. fifony infers the right agent from the issue description and target file paths — capability routing is automatic.
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# Manage reference repositories from the CLI
|
|
187
|
+
fifony onboarding list # list repos and sync status
|
|
188
|
+
fifony onboarding sync # sync all
|
|
189
|
+
fifony onboarding sync --repository ring # sync one
|
|
190
|
+
fifony onboarding import ring --kind agents # import agents
|
|
191
|
+
fifony onboarding import impeccable --kind skills # import skills
|
|
192
|
+
fifony onboarding import agency-agents --kind agents --overwrite # overwrite existing
|
|
193
|
+
```
|
|
122
194
|
|
|
123
195
|
---
|
|
124
196
|
|
|
125
197
|
## CLI Reference
|
|
126
198
|
|
|
127
199
|
```bash
|
|
128
|
-
# Dashboard + API
|
|
129
|
-
npx -y fifony
|
|
200
|
+
# Dashboard + API (default port 4000)
|
|
201
|
+
npx -y fifony
|
|
130
202
|
|
|
131
|
-
#
|
|
132
|
-
npx -y fifony --port
|
|
203
|
+
# Custom port
|
|
204
|
+
npx -y fifony --port 8080
|
|
133
205
|
|
|
134
|
-
#
|
|
135
|
-
npx -y fifony
|
|
206
|
+
# With Vite HMR for frontend development
|
|
207
|
+
npx -y fifony --dev
|
|
136
208
|
|
|
137
209
|
# MCP server (stdio)
|
|
138
210
|
npx -y fifony mcp
|
|
139
211
|
|
|
140
212
|
# Different workspace
|
|
141
|
-
npx -y fifony --workspace /path/to/repo
|
|
213
|
+
npx -y fifony --workspace /path/to/repo
|
|
142
214
|
|
|
143
215
|
# Run one scheduler cycle and exit
|
|
144
216
|
npx -y fifony --once
|
|
145
217
|
|
|
146
218
|
# Fine-grained control
|
|
147
219
|
npx -y fifony --concurrency 2 --attempts 3 --poll 500
|
|
148
|
-
|
|
149
|
-
# Onboarding reference repositories
|
|
150
|
-
fifony onboarding list
|
|
151
|
-
fifony onboarding sync
|
|
152
|
-
fifony onboarding sync --repository ring
|
|
153
|
-
fifony onboarding import ring --kind skills
|
|
154
|
-
fifony onboarding import agency-agents --kind agents --overwrite
|
|
155
220
|
```
|
|
156
221
|
|
|
157
222
|
---
|
|
@@ -177,36 +242,17 @@ Add to `claude_desktop_config.json` or VS Code settings:
|
|
|
177
242
|
}
|
|
178
243
|
```
|
|
179
244
|
|
|
180
|
-
**Resources**: state
|
|
245
|
+
**Resources**: `fifony://state/summary`, `fifony://issues`, `fifony://issue/{id}`, `fifony://issue/{id}/plan`, `fifony://issue/{id}/diff`, `fifony://issue/{id}/events`, `fifony://workflow/config`, `fifony://analytics`, `fifony://guide/overview`, `fifony://guide/runtime`, `fifony://guide/integration`, `fifony://integrations`, `fifony://capabilities`, `fifony://agents/catalog`, `fifony://skills/catalog`, `fifony://events/recent`
|
|
181
246
|
|
|
182
|
-
**Tools**: `fifony.status`, `fifony.list_issues`, `fifony.create_issue`, `fifony.update_issue_state`, `fifony.integration_config`
|
|
247
|
+
**Tools**: `fifony.status`, `fifony.list_issues`, `fifony.create_issue`, `fifony.get_issue`, `fifony.update_issue_state`, `fifony.cancel_issue`, `fifony.retry_issue`, `fifony.plan`, `fifony.refine`, `fifony.approve`, `fifony.merge`, `fifony.get_diff`, `fifony.get_live`, `fifony.get_events`, `fifony.enhance`, `fifony.analytics`, `fifony.resolve_capabilities`, `fifony.get_workflow`, `fifony.scan_project`, `fifony.install_agents`, `fifony.install_skills`, `fifony.integration_config`, `fifony.list_integrations`, `fifony.integration_snippet`
|
|
183
248
|
|
|
184
|
-
**Prompts**: `fifony-integrate-client`, `fifony-plan-issue`, `fifony-
|
|
249
|
+
**Prompts**: `fifony-integrate-client`, `fifony-plan-issue`, `fifony-route-task`, `fifony-use-integration`, `fifony-diagnose-blocked`, `fifony-weekly-summary`, `fifony-refine-plan`, `fifony-code-review`
|
|
185
250
|
|
|
186
251
|
---
|
|
187
252
|
|
|
188
253
|
## REST API
|
|
189
254
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
| Endpoint | Description |
|
|
193
|
-
|----------|-------------|
|
|
194
|
-
| `GET /api/state` | Full runtime state: issues, metrics, config |
|
|
195
|
-
| `POST /api/issues/create` | Create an issue |
|
|
196
|
-
| `POST /api/issues/enhance` | AI-enhance title and description |
|
|
197
|
-
| `POST /api/issues/:id/plan` | Generate execution plan |
|
|
198
|
-
| `POST /api/issues/:id/plan/refine` | Refine plan with chat feedback |
|
|
199
|
-
| `POST /api/issues/:id/approve` | Approve plan, start execution |
|
|
200
|
-
| `POST /api/issues/:id/merge` | Merge workspace to project root |
|
|
201
|
-
| `GET /api/live/:id` | Live agent output: PID, log tail, elapsed time |
|
|
202
|
-
| `GET /api/diff/:id` | Git diff of workspace changes |
|
|
203
|
-
| `GET /api/config/workflow` | Pipeline workflow configuration |
|
|
204
|
-
| `GET /api/analytics/tokens` | Token usage summary |
|
|
205
|
-
| `GET /api/analytics/hourly` | Hourly usage buckets (48h retention) |
|
|
206
|
-
| `GET /api/providers` | Detected providers and availability |
|
|
207
|
-
| `GET /api/catalog/agents` | Agent catalog, filterable by domain |
|
|
208
|
-
| `POST /api/install/agents` | Install agents to project |
|
|
209
|
-
| `/ws` | WebSocket for real-time state updates |
|
|
255
|
+
All endpoints are auto-documented via the s3db.js ApiPlugin. Open **http://localhost:4000/docs** for the interactive OpenAPI explorer with request/response schemas, try-it-out forms, and WebSocket details.
|
|
210
256
|
|
|
211
257
|
---
|
|
212
258
|
|
|
@@ -223,6 +269,7 @@ FIFONY_AGENT_PROVIDER=codex # codex | claude
|
|
|
223
269
|
FIFONY_WORKER_CONCURRENCY=2
|
|
224
270
|
FIFONY_MAX_ATTEMPTS=3
|
|
225
271
|
FIFONY_AGENT_MAX_TURNS=4
|
|
272
|
+
FIFONY_LOG_FILE=0 # set to 1 to also write .fifony/fifony-local.log
|
|
226
273
|
```
|
|
227
274
|
|
|
228
275
|
---
|
|
@@ -232,50 +279,26 @@ FIFONY_AGENT_MAX_TURNS=4
|
|
|
232
279
|
```
|
|
233
280
|
.fifony/
|
|
234
281
|
s3db/ ← durable database (issues, events, sessions, settings)
|
|
235
|
-
source/ ← project snapshot
|
|
236
|
-
workspaces/ ←
|
|
282
|
+
source/ ← project snapshot for diff reference
|
|
283
|
+
workspaces/ ← per-issue git worktrees
|
|
237
284
|
```
|
|
238
285
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
- `eventsCount`,
|
|
249
|
-
- `linesAdded`, `linesRemoved`, `filesChanged`.
|
|
250
|
-
- We query this through `getLastNDays/getLastNHours` to feed `/api/analytics/lines` and `/api/analytics/tokens`.
|
|
251
|
-
- **Issue lifecycle in StateMachinePlugin (single source of truth):**
|
|
252
|
-
- States, guarded transitions, actions, and triggers are centralized in `issue-state-machine.ts`.
|
|
253
|
-
- Public commands (`approve`, `execute`, `queue`, `retry`, `merge`) only emit transitions; the workflow behavior is not duplicated in route handlers.
|
|
254
|
-
- The machine also owns interruption recovery, retry delays, terminal transitions, and rollback edges.
|
|
255
|
-
- **Queue and execution pool:**
|
|
256
|
-
- `s3queue` is the runtime queue adapter with polling workers.
|
|
257
|
-
- Workers consume planning/execution/review jobs and run concurrently respecting configured concurrency.
|
|
258
|
-
- **Agent abstraction:**
|
|
259
|
-
- fifony wraps local CLIs, not proprietary model logic.
|
|
260
|
-
- Per stage we configure `cli`, `model`, and `reasoningEffort` independently (`planning`, `execute`, `review`).
|
|
261
|
-
- This lets you swap providers by issue without changing core orchestration.
|
|
262
|
-
- **Per-issue isolation:**
|
|
263
|
-
- Each issue has its own execution workspace and Git worktree branch.
|
|
264
|
-
- That avoids file conflicts and enables parallel work on the same repo safely.
|
|
265
|
-
- **Review and execution observability:**
|
|
266
|
-
- Diff stats are computed from git `--stat` output (`linesAdded`, `linesRemoved`, `filesChanged`).
|
|
267
|
-
- Runtime events are emitted for state transitions, review path decisions, and merge outcomes.
|
|
268
|
-
- CLI output and audit trails are stored to make mid-run interruptions recoverable.
|
|
269
|
-
- **Capability routing:**
|
|
270
|
-
- Routing derives issue labels (`capability:<category>`, `overlay:<name>`) from issue text and inferred file paths.
|
|
271
|
-
- This improves queue triage and worker assignment.
|
|
286
|
+
| Layer | How it works |
|
|
287
|
+
|-------|-------------|
|
|
288
|
+
| **State machine** | 11 states, 14 events. States named by actor: AI (Planning, Running, Reviewing), Human (PendingApproval, PendingDecision, Approved), terminal (Merged, Cancelled, Archived). Archived = soft-delete, hidden from all views. |
|
|
289
|
+
| **Unified queue** | Single work queue with phase ordering (review → execute → plan). Semaphore for concurrency. No scheduler loop — event-driven dispatch. Planning runs outside the semaphore. |
|
|
290
|
+
| **Persistence** | s3db.js with SQLite backend. Issues, events, sessions, and settings are first-class resources. No external DB. |
|
|
291
|
+
| **Analytics** | `EventualConsistencyPlugin` tracks token usage, code churn (lines added/removed), and event counts with daily cohort rollups. |
|
|
292
|
+
| **Agents** | Wraps local CLIs (Claude, Codex, Gemini). Per-stage provider, model, and reasoning effort. No proprietary model logic. |
|
|
293
|
+
| **Isolation** | Each issue gets its own git worktree branch. Parallel work on the same repo without file conflicts. |
|
|
294
|
+
| **Routing** | Capability labels derived from issue text and file paths drive automatic agent/provider selection. |
|
|
272
295
|
|
|
273
296
|
---
|
|
274
297
|
|
|
275
298
|
## Requirements
|
|
276
299
|
|
|
277
300
|
- Node.js 23 or newer
|
|
278
|
-
- At least one of: `claude` CLI, `codex` CLI
|
|
301
|
+
- At least one of: `claude` CLI, `codex` CLI, `gemini` CLI
|
|
279
302
|
|
|
280
303
|
---
|
|
281
304
|
|
package/app/dist/assets/{KeyboardShortcutsHelp-lTNj9GiT.js → KeyboardShortcutsHelp-By0KcDhZ.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e}from"./rolldown-runtime-DF2fYuay.js";import{I as t,h as n}from"./vendor-
|
|
1
|
+
import{n as e}from"./rolldown-runtime-DF2fYuay.js";import{I as t,h as n}from"./vendor-D-IqxHHu.js";import{t as r}from"./createLucideIcon-DgMTp0yx.js";import{r as i}from"./index-59O8esMr.js";var a=r(`keyboard`,[[`path`,{d:`M10 8h.01`,key:`1r9ogq`}],[`path`,{d:`M12 12h.01`,key:`1mp3jc`}],[`path`,{d:`M14 8h.01`,key:`1primd`}],[`path`,{d:`M16 12h.01`,key:`1l6xoz`}],[`path`,{d:`M18 8h.01`,key:`emo2bl`}],[`path`,{d:`M6 8h.01`,key:`x9i8wu`}],[`path`,{d:`M7 16h10`,key:`wp8him`}],[`path`,{d:`M8 12h.01`,key:`czm47f`}],[`rect`,{width:`20`,height:`16`,x:`2`,y:`4`,rx:`2`,key:`18n3k1`}]]),o=e(t(),1),s=n(),c=[{key:`n`,description:`Open New Issue drawer`},{key:`k`,description:`Navigate to Kanban`},{key:`i`,description:`Navigate to Issues`},{key:`a`,description:`Navigate to Agents`},{key:`t`,description:`Navigate to Analytics`},{key:`s`,description:`Navigate to Settings`},{key:`1–6`,description:`Jump to kanban column by index`},{key:`Esc`,description:`Close any open drawer / modal`},{key:`?`,description:`Show this help`}];function l({open:e,onClose:t}){let n=(0,o.useRef)(null);return(0,o.useEffect)(()=>{let t=n.current;t&&(e&&!t.open?t.showModal():!e&&t.open&&t.close())},[e]),(0,s.jsxs)(`dialog`,{ref:n,className:`modal modal-bottom sm:modal-middle`,onClose:t,children:[(0,s.jsxs)(`div`,{className:`modal-box max-w-md`,children:[(0,s.jsxs)(`div`,{className:`flex items-center justify-between mb-4`,children:[(0,s.jsxs)(`h3`,{className:`font-bold text-lg flex items-center gap-2`,children:[(0,s.jsx)(a,{className:`size-5 opacity-60`}),`Keyboard Shortcuts`]}),(0,s.jsx)(`button`,{className:`btn btn-sm btn-ghost btn-circle`,onClick:t,children:(0,s.jsx)(i,{className:`size-4`})})]}),(0,s.jsx)(`div`,{className:`overflow-x-auto`,children:(0,s.jsxs)(`table`,{className:`table table-sm`,children:[(0,s.jsx)(`thead`,{children:(0,s.jsxs)(`tr`,{children:[(0,s.jsx)(`th`,{children:`Key`}),(0,s.jsx)(`th`,{children:`Action`})]})}),(0,s.jsx)(`tbody`,{children:c.map(e=>(0,s.jsxs)(`tr`,{children:[(0,s.jsx)(`td`,{children:(0,s.jsx)(`kbd`,{className:`kbd kbd-sm`,children:e.key})}),(0,s.jsx)(`td`,{children:e.description})]},e.key))})]})}),(0,s.jsx)(`div`,{className:`modal-action`,children:(0,s.jsx)(`button`,{className:`btn btn-sm`,onClick:t,children:`Close`})})]}),(0,s.jsx)(`form`,{method:`dialog`,className:`modal-backdrop`,children:(0,s.jsx)(`button`,{children:`close`})})]})}export{l as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e}from"./rolldown-runtime-DF2fYuay.js";import{I as t,h as n,m as r}from"./vendor-D-IqxHHu.js";import{t as i}from"./createLucideIcon-DgMTp0yx.js";import{A as a,B as o,C as s,D as c,E as l,F as u,H as d,I as f,L as p,M as m,N as h,O as g,P as _,T as v,W as y,_ as b,a as x,b as S,c as C,d as w,f as T,h as E,i as D,j as O,l as k,n as A,p as j,t as ee,u as M,v as N,w as te,y as ne}from"./index-59O8esMr.js";var P=i(`brain`,[[`path`,{d:`M12 18V5`,key:`adv99a`}],[`path`,{d:`M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4`,key:`1e3is1`}],[`path`,{d:`M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5`,key:`1gqd8o`}],[`path`,{d:`M17.997 5.125a4 4 0 0 1 2.526 5.77`,key:`iwvgf7`}],[`path`,{d:`M18 18a4 4 0 0 0 2-7.464`,key:`efp6ie`}],[`path`,{d:`M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517`,key:`1gq6am`}],[`path`,{d:`M6 18a4 4 0 0 1-2-7.464`,key:`k1g0md`}],[`path`,{d:`M6.003 5.125a4 4 0 0 0-2.526 5.77`,key:`q97ue3`}]]),F=i(`chevron-left`,[[`path`,{d:`m15 18-6-6 6-6`,key:`1wnfg3`}]]),I=i(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]),L=i(`flame`,[[`path`,{d:`M12 3q1 4 4 6.5t3 5.5a1 1 0 0 1-14 0 5 5 0 0 1 1-3 1 1 0 0 0 5 0c0-2-1.5-3-1.5-5q0-2 2.5-4`,key:`1slcih`}]]),re=i(`folder-root`,[[`path`,{d:`M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z`,key:`1fr9dc`}],[`circle`,{cx:`12`,cy:`13`,r:`2`,key:`1c1ljs`}],[`path`,{d:`M12 15v5`,key:`11xva1`}]]),R=i(`pencil-line`,[[`path`,{d:`M13 21h8`,key:`1jsn5i`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}],[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}]]),z=i(`rocket`,[[`path`,{d:`M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5`,key:`qeys4`}],[`path`,{d:`M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09`,key:`u4xsad`}],[`path`,{d:`M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z`,key:`676m9`}],[`path`,{d:`M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05`,key:`92ym6u`}]]),B=i(`shield-check`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),V=e(t(),1),H=n();function ie(){let e=(0,V.useRef)(null),t=(0,V.useRef)([]),n=(0,V.useRef)(null);return(0,V.useEffect)(()=>{let r=e.current;if(!r)return;let i=r.getContext(`2d`),a=[`♪`,`♫`,`♩`,`♬`],o=[`oklch(0.75 0.18 250)`,`oklch(0.80 0.16 200)`,`oklch(0.70 0.20 330)`,`oklch(0.85 0.14 85)`,`oklch(0.75 0.18 145)`,`oklch(0.80 0.12 280)`,`oklch(0.78 0.15 30)`],s=o.length,c=a.length,l=document.createElement(`canvas`);l.width=s*56,l.height=c*56;let u=l.getContext(`2d`);u.textAlign=`center`,u.textBaseline=`middle`,u.font=`48px serif`;let d=[];for(let e=0;e<c;e++){d[e]=[];for(let t=0;t<s;t++){let n=t*56+56/2,r=e*56+56/2;u.fillStyle=o[t],u.fillText(a[e],n,r),d[e][t]={x:t*56,y:e*56}}}let f=0,p=0,m=()=>{let e=window.devicePixelRatio||1;f=window.innerWidth,p=window.innerHeight,r.width=f*e,r.height=p*e,r.style.width=f+`px`,r.style.height=p+`px`,i.setTransform(e,0,0,e,0,0)};m();function h(){let e=f/2,t=p*.38,n=Math.random()*Math.PI*2,r=Math.random()*1.8+.4,i=Math.random()*20,a=Math.floor(Math.random()*c),o=Math.floor(Math.random()*s);return{x:e+Math.cos(n)*i,y:t+Math.sin(n)*i,vx:Math.cos(n)*r,vy:Math.sin(n)*r,gravity:.003+Math.random()*.005,scale:Math.random()*.4+.25,si:a,ci:o,rotation:Math.random()*Math.PI*2,rotationSpeed:(Math.random()-.5)*.04,life:0,maxLife:180+Math.random()*200,fadeIn:15}}let g=Math.min(Math.floor(f*p/6e3),120);t.current=[];for(let e=0;e<g;e++){let e=h(),n=Math.random()*e.maxLife*.8;e.x+=e.vx*n,e.y+=e.vy*n+.5*e.gravity*n*n,e.rotation+=e.rotationSpeed*n,e.life=n,t.current.push(e)}let _=Math.max(1,Math.floor(g/90)),v=0,y=()=>{if(i.clearRect(0,0,f,p),v++,v%2==0)for(let e=0;e<_;e++)t.current.push(h());let e=[];for(let n of t.current){if(n.life++,n.x+=n.vx,n.y+=n.vy,n.vy+=n.gravity,n.rotation+=n.rotationSpeed,n.vx*=.998,n.vy*=.998,n.life>n.maxLife||n.x<-60||n.x>f+60||n.y<-60||n.y>p+60)continue;e.push(n);let t=Math.min(1,n.life/n.fadeIn),r=n.maxLife*.6,a=t*(n.life>r?1-(n.life-r)/(n.maxLife-r):1)*.45;if(a<=.01)continue;let o=d[n.si][n.ci],s=56*n.scale,c=s/2;i.save(),i.translate(n.x,n.y),i.rotate(n.rotation),i.globalAlpha=a,i.drawImage(l,o.x,o.y,56,56,-c,-c,s,s),i.restore()}t.current=e,n.current=requestAnimationFrame(y)};return n.current=requestAnimationFrame(y),window.addEventListener(`resize`,m),()=>{cancelAnimationFrame(n.current),window.removeEventListener(`resize`,m)}},[]),(0,H.jsx)(`canvas`,{ref:e,className:`fixed inset-0 pointer-events-none`,style:{zIndex:0},"aria-hidden":`true`})}var U=[`Welcome`,`Setup`,`Pipeline`,`Agents & Skills`,`Preferences`,`Launch`];function ae(){return U}function oe(){return U.length}var W=[`Setup`,`Pipeline`,`Agents`,`Preferences`,`Launch`];function G(){return W}var K=[{value:`low`,label:`Low`,icon:A,description:`Quick and light -- fast responses, less thorough`,color:`text-info`},{value:`medium`,label:`Medium`,icon:ne,description:`Balanced -- good mix of speed and quality`,color:`text-success`},{value:`high`,label:`High`,icon:P,description:`Thorough -- deeper analysis, takes more time`,color:`text-warning`},{value:`extra-high`,label:`Extra High`,icon:L,description:`Maximum depth -- most thorough, slowest`,color:`text-error`}],se={codex:K,claude:K.filter(e=>e.value!==`extra-high`),gemini:K.filter(e=>e.value!==`extra-high`)};function q(e,t){return se[t?.[e]||`codex`]||K}var J=[{value:`auto`,label:`Auto`},{value:`light`,label:`Light`},{value:`dark`,label:`Dark`},{value:`black`,label:`Black`},{value:`cupcake`,label:`Cupcake`},{value:`night`,label:`Night`},{value:`sunset`,label:`Sunset`}],Y=[{role:`planner`,label:`Planner`,description:`Scopes the issue, breaks it into steps, and decides the approach`,icon:P,color:`text-info`},{role:`executor`,label:`Executor`,description:`Implements the plan — writes code, edits files, runs commands`,icon:A,color:`text-primary`},{role:`reviewer`,label:`Reviewer`,description:`Validates the result — checks correctness, scope, and quality`,icon:k,color:`text-secondary`}];async function X(e,t,n=`ui`){return d.post(`/settings/${encodeURIComponent(e)}`,{value:t,scope:n,source:`user`})}function Z(e,t=`medium`){return K.some(t=>t.value===e)?e:t}function ce(e){return!e||typeof e!=`object`||Array.isArray(e)?{planner:`medium`,executor:`medium`,reviewer:`medium`}:{planner:Z(e.planner??e.default,`medium`),executor:Z(e.executor??e.default,`medium`),reviewer:Z(e.reviewer??e.default,`medium`)}}function le(e,t,n={}){return{plan:{provider:e.planner||e.executor||``,model:n.plan||``,effort:t.planner||`medium`},execute:{provider:e.executor||``,model:n.execute||``,effort:t.executor||`medium`},review:{provider:e.reviewer||e.executor||``,model:n.review||``,effort:t.reviewer||`medium`}}}function ue({current:e}){let t=G(),n=e-1;return(0,H.jsx)(`ul`,{className:`steps steps-horizontal w-full max-w-2xl text-xs`,children:t.map((e,t)=>{let r=t<n,i=t===n;return(0,H.jsx)(`li`,{"data-content":r?`✓`:t+1,className:`step ${r||i?`step-primary`:``}`,style:{transition:`color 0.3s ease`},children:e},e)})})}function de({direction:e,stepKey:t,center:n,children:r}){return(0,H.jsx)(`div`,{className:`${e===`forward`?`animate-slide-in-right`:`animate-slide-in-left`} w-full max-w-2xl mx-auto ${n?`my-auto`:``}`,children:r},t)}function fe({step:e,stepCount:t,stepName:n,canProceed:r,launching:i,onBack:a,onNext:o,onLaunch:s}){return e===0?null:(0,H.jsxs)(`div`,{className:`relative z-10 p-4 pb-6 flex items-center max-w-2xl mx-auto w-full justify-between`,children:[(0,H.jsxs)(`button`,{className:`btn btn-ghost gap-1`,onClick:a,disabled:i,children:[(0,H.jsx)(F,{className:`size-4`}),` Back`]}),e<t-1?(0,H.jsxs)(`button`,{className:`btn btn-primary gap-1`,onClick:o,disabled:!r,children:[`Next `,(0,H.jsx)(I,{className:`size-4`})]}):(0,H.jsx)(`button`,{className:`btn btn-primary btn-lg gap-2 animate-pulse-soft`,onClick:s,disabled:i,children:i?(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(j,{className:`size-5 animate-spin`}),` Launching...`]}):(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(z,{className:`size-5`}),` Launch fifony`]})})]})}function pe({workspacePath:e,onGetStarted:t}){return(0,H.jsxs)(`div`,{className:`flex flex-col items-center text-center gap-6 stagger-children py-4`,children:[(0,H.jsx)(`img`,{src:y,alt:`fifony mascot`,className:`h-72 sm:h-96 object-contain animate-bounce-in select-none pointer-events-none`,style:{filter:`drop-shadow(0 12px 40px rgba(128, 0, 255, 0.3))`}}),(0,H.jsxs)(`h1`,{className:`text-4xl sm:text-5xl font-bold tracking-tight leading-none`,style:{fontFamily:`'Space Grotesk', system-ui, sans-serif`},children:[`Welcome to `,(0,H.jsx)(`span`,{className:`text-primary`,children:`fifony`})]}),(0,H.jsx)(`p`,{className:`text-base-content/60 text-lg max-w-md`,children:`Let's set up your AI orchestration project in just a few steps.`}),e&&(0,H.jsxs)(`div`,{className:`badge badge-lg badge-soft badge-primary gap-2`,children:[(0,H.jsx)(C,{className:`size-3.5`}),`Project target: `,e]}),(0,H.jsxs)(`button`,{className:`btn btn-primary btn-lg gap-2 mt-2`,onClick:t,children:[`Get Started `,(0,H.jsx)(I,{className:`size-5`})]})]})}var me=new Set([`main`,`master`]);function he(){let[e,t]=(0,V.useState)(null),[n,r]=(0,V.useState)(!1),[i,a]=(0,V.useState)(!1);return(0,V.useEffect)(()=>{d.get(`/gitignore/status`).then(t).catch(()=>t({exists:!1,hasFifony:!1}))},[]),e===null||e.hasFifony?null:i?(0,H.jsxs)(`div`,{className:`alert alert-success py-2.5 text-sm animate-fade-in`,children:[(0,H.jsx)(B,{className:`size-4 shrink-0`}),(0,H.jsxs)(`span`,{children:[(0,H.jsx)(`code`,{children:`.fifony/`}),` adicionado ao `,(0,H.jsx)(`code`,{children:`.gitignore`})]})]}):(0,H.jsxs)(`div`,{className:`alert alert-warning py-2.5 text-sm`,children:[(0,H.jsx)(B,{className:`size-4 shrink-0`}),(0,H.jsxs)(`div`,{className:`flex-1`,children:[(0,H.jsxs)(`span`,{children:[(0,H.jsx)(`code`,{children:`.fifony/`}),` não está no `,(0,H.jsx)(`code`,{children:`.gitignore`})]}),(0,H.jsx)(`span`,{className:`text-base-content/50 block text-xs mt-0.5`,children:`O fifony guarda estado local lá — não deve ser commitado.`})]}),(0,H.jsx)(`button`,{className:`btn btn-xs btn-warning`,onClick:async()=>{r(!0);try{await d.post(`/gitignore/add`),a(!0)}catch{}finally{r(!1)}},disabled:n,children:n?(0,H.jsx)(j,{className:`size-3 animate-spin`}):`Adicionar`})]})}function ge({currentBranch:e,onBranchCreated:t}){let[n,r]=(0,V.useState)(null),[i,a]=(0,V.useState)(!1),[o,s]=(0,V.useState)(null),[c,l]=(0,V.useState)(e);(0,V.useEffect)(()=>{d.get(`/git/status`).then(e=>{r(e),e.branch&&l(e.branch)}).catch(()=>r({isGit:!0,branch:e,hasCommits:!0}))},[]);let[u,f]=(0,V.useState)(!1),[p,m]=(0,V.useState)(``),[h,g]=(0,V.useState)(!1),[_,y]=(0,V.useState)(null),[S,C]=(0,V.useState)(null),w=n===null||n.isGit,E=me.has(c),D=p.trim(),O=/^[a-zA-Z0-9/_.-]+$/.test(D)&&D.length>0,k=D===c;function A(){f(!0),m(c||``),y(null),C(null)}async function ee(){if(!(!O||k||h)){g(!0),y(null);try{let e=await d.post(`/git/switch`,{branchName:D});if(!e.ok)throw Error(e.error||`Failed to switch branch.`);l(D),C({branch:D,created:e.created}),f(!1),t?.(D)}catch(e){y(e instanceof Error?e.message:String(e))}finally{g(!1)}}}async function M(){a(!0),s(null);try{let e=await d.post(`/git/init`,{});if(!e.ok)throw Error(e.error||`Failed to initialize git.`);r({isGit:!0,branch:e.branch,hasCommits:!0}),l(e.branch)}catch(e){s(e instanceof Error?e.message:String(e))}finally{a(!1)}}return(0,H.jsxs)(`div`,{className:`bg-base-200 rounded-2xl p-5 flex flex-col gap-4`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(N,{className:`size-4 text-primary`}),(0,H.jsx)(`div`,{className:`text-sm font-semibold`,children:`Working branch`})]}),(0,H.jsx)(`p`,{className:`text-xs text-base-content/50 -mt-2`,children:`Agents create worktrees based on the current branch. We recommend not working directly on main.`}),n!==null&&!n.isGit&&(0,H.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[(0,H.jsxs)(`div`,{className:`alert alert-warning py-3`,children:[(0,H.jsx)(b,{className:`size-4 shrink-0`}),(0,H.jsxs)(`div`,{className:`text-sm`,children:[(0,H.jsx)(`p`,{className:`font-semibold`,children:`Not a git repository`}),(0,H.jsx)(`p`,{className:`opacity-80 mt-0.5`,children:`fifony requires git to create agent worktrees. Initialize one here.`})]})]}),o&&(0,H.jsxs)(`p`,{className:`text-xs text-error flex items-center gap-1`,children:[(0,H.jsx)(x,{className:`size-3`}),` `,o]}),(0,H.jsxs)(`button`,{className:`btn btn-primary gap-2 self-start`,onClick:M,disabled:i,children:[i?(0,H.jsx)(j,{className:`size-4 animate-spin`}):(0,H.jsx)(b,{className:`size-4`}),`Initialize git repository`]})]}),w&&(0,H.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[u?(0,H.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,H.jsxs)(`div`,{className:`flex gap-2`,children:[(0,H.jsxs)(`label`,{className:`input input-bordered flex items-center gap-2 flex-1`,children:[(0,H.jsx)(N,{className:`size-3.5 opacity-40`}),(0,H.jsx)(`input`,{type:`text`,className:`grow font-mono text-sm`,value:p,onChange:e=>{m(e.target.value),y(null)},onKeyDown:e=>{e.key===`Enter`&&ee(),e.key===`Escape`&&(f(!1),y(null))},placeholder:`develop`,autoFocus:!0,disabled:h})]}),(0,H.jsx)(`button`,{className:`btn btn-primary`,onClick:ee,disabled:!O||k||h,children:h?(0,H.jsx)(T,{className:`size-4 animate-spin`}):`Switch`}),(0,H.jsx)(`button`,{className:`btn btn-ghost`,onClick:()=>{f(!1),y(null)},disabled:h,children:`Cancel`})]}),_&&(0,H.jsxs)(`p`,{className:`text-xs text-error flex items-center gap-1`,children:[(0,H.jsx)(x,{className:`size-3`}),` `,_]}),(0,H.jsx)(`p`,{className:`text-xs opacity-40`,children:`Switches to the branch if it exists, or creates it from the current HEAD.`})]}):(0,H.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-3 rounded-box border border-base-300 bg-base-100 cursor-pointer hover:border-primary/40 transition-colors group`,onClick:A,role:`button`,tabIndex:0,onKeyDown:e=>e.key===`Enter`&&A(),children:[(0,H.jsx)(N,{className:`size-4 opacity-50 shrink-0`}),(0,H.jsx)(`span`,{className:`text-sm opacity-50`,children:`Current branch:`}),(0,H.jsx)(`span`,{className:`font-mono text-sm font-semibold`,children:c||(n===null?`…`:`—`)}),E&&(0,H.jsx)(`span`,{className:`badge badge-warning badge-sm ml-auto shrink-0`,children:`protected`}),!E&&(0,H.jsx)(R,{className:`size-3.5 opacity-0 group-hover:opacity-40 ml-auto shrink-0 transition-opacity`})]}),S&&(0,H.jsxs)(`div`,{className:`alert alert-success py-3 text-sm animate-fade-in`,children:[(0,H.jsx)(v,{className:`size-4 shrink-0`}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`p`,{className:`font-semibold`,children:S.created?`Branch created`:`Switched to branch`}),(0,H.jsxs)(`p`,{className:`opacity-75 font-mono mt-0.5`,children:[`Now on `,(0,H.jsx)(`span`,{className:`text-success-content`,children:S.branch}),` — agents will use this as the base branch`]})]})]}),E&&!u&&(0,H.jsxs)(`div`,{className:`alert alert-warning py-3`,children:[(0,H.jsx)(x,{className:`size-4 shrink-0`}),(0,H.jsxs)(`div`,{className:`text-sm`,children:[(0,H.jsxs)(`p`,{className:`font-semibold`,children:[`Working directly on `,(0,H.jsx)(`span`,{className:`font-mono`,children:c})]}),(0,H.jsx)(`p`,{className:`opacity-80 mt-0.5`,children:`In teams with protected branches, local merges are rejected. Click the branch above to switch, or use Push PR mode.`})]})]}),(0,H.jsx)(he,{})]})]})}function _e({mergeMode:e,setMergeMode:t,prBaseBranch:n,setPrBaseBranch:r,currentBranch:i}){return(0,H.jsxs)(`div`,{className:`bg-base-200 rounded-2xl p-5 flex flex-col gap-4`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(E,{className:`size-4 text-primary`}),(0,H.jsx)(`div`,{className:`text-sm font-semibold`,children:`Merge mode`})]}),(0,H.jsx)(`p`,{className:`text-xs text-base-content/50 -mt-2`,children:`Choose how completed issues are integrated: local git merge or push a PR to GitHub.`}),(0,H.jsxs)(`div`,{className:`flex gap-3`,children:[(0,H.jsxs)(`label`,{className:`flex-1 cursor-pointer rounded-xl border-2 p-3 text-center text-sm font-medium transition-colors ${e===`local`?`border-primary bg-primary/10`:`border-base-300 bg-base-100`}`,children:[(0,H.jsx)(`input`,{type:`radio`,name:`mergeMode`,className:`hidden`,checked:e===`local`,onChange:()=>t(`local`)}),(0,H.jsx)(b,{className:`size-4 mx-auto mb-1 opacity-60`}),`Local merge`]}),(0,H.jsxs)(`label`,{className:`flex-1 cursor-pointer rounded-xl border-2 p-3 text-center text-sm font-medium transition-colors ${e===`push-pr`?`border-primary bg-primary/10`:`border-base-300 bg-base-100`}`,children:[(0,H.jsx)(`input`,{type:`radio`,name:`mergeMode`,className:`hidden`,checked:e===`push-pr`,onChange:()=>t(`push-pr`)}),(0,H.jsx)(E,{className:`size-4 mx-auto mb-1 opacity-60`}),`Push PR`]})]}),e===`push-pr`&&(0,H.jsxs)(`label`,{className:`form-control w-full gap-2`,children:[(0,H.jsx)(`span`,{className:`label-text text-sm font-medium`,children:`PR base branch`}),(0,H.jsx)(`input`,{type:`text`,className:`input input-bordered w-full text-sm font-mono`,placeholder:i||`main`,value:n,onChange:e=>r(e.target.value)}),(0,H.jsx)(`p`,{className:`text-xs opacity-40`,children:`Branch that PRs will target. Defaults to the current branch.`})]})]})}function Q({testCommand:e,setTestCommand:t}){return(0,H.jsxs)(`div`,{className:`bg-base-200 rounded-2xl p-5 flex flex-col gap-4`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(S,{className:`size-4 text-primary`}),(0,H.jsx)(`div`,{className:`text-sm font-semibold`,children:`Test command`})]}),(0,H.jsx)(`p`,{className:`text-xs text-base-content/50 -mt-2`,children:`Validation gate: this command runs before merge/done. Leave empty to skip.`}),(0,H.jsx)(`input`,{type:`text`,className:`input input-bordered w-full text-sm font-mono`,placeholder:`pnpm test`,value:e,onChange:e=>t(e.target.value)})]})}function ve({projectName:e,setProjectName:t,detectedProjectName:n,projectSource:r,workspacePath:i,currentBranch:a,onBranchCreated:o,mergeMode:s,setMergeMode:c,prBaseBranch:l,setPrBaseBranch:u,testCommand:d,setTestCommand:f}){let p=m(e),h=O(p||n),g=p?r===`saved`||r===`detected`?r:`manual`:n?`detected`:`missing`;return(0,H.jsxs)(`div`,{className:`flex flex-col gap-6 py-4`,children:[(0,H.jsxs)(`div`,{className:`text-center space-y-3`,children:[(0,H.jsx)(`div`,{className:`inline-flex size-14 items-center justify-center rounded-full bg-primary/10 text-primary mx-auto`,children:(0,H.jsx)(re,{className:`size-7`})}),(0,H.jsxs)(`div`,{className:`space-y-2`,children:[(0,H.jsx)(`h2`,{className:`text-2xl font-bold tracking-tight`,children:`Set up your workspace`}),(0,H.jsx)(`p`,{className:`text-base-content/60 max-w-xl mx-auto text-sm`,children:`Name your project and configure the working branch`})]})]}),(0,H.jsxs)(`div`,{className:`bg-base-200 rounded-2xl p-5 flex flex-col gap-4`,children:[(0,H.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:[(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-sm font-semibold`,children:`Project name`}),(0,H.jsx)(`div`,{className:`text-xs text-base-content/50`,children:`This becomes the default queue title for future runs.`})]}),g===`saved`&&(0,H.jsxs)(`span`,{className:`badge badge-primary badge-soft gap-1.5`,children:[(0,H.jsx)(C,{className:`size-3`}),`Saved configuration`]}),g===`detected`&&(0,H.jsxs)(`span`,{className:`badge badge-secondary badge-soft gap-1.5`,children:[(0,H.jsx)(C,{className:`size-3`}),`Detected automatically`]}),g===`manual`&&(0,H.jsxs)(`span`,{className:`badge badge-accent badge-soft gap-1.5`,children:[(0,H.jsx)(R,{className:`size-3`}),`Edited manually`]}),g===`missing`&&(0,H.jsxs)(`span`,{className:`badge badge-warning badge-soft gap-1.5`,children:[(0,H.jsx)(x,{className:`size-3`}),`Manual entry required`]})]}),(0,H.jsxs)(`label`,{className:`form-control w-full gap-2`,children:[(0,H.jsx)(`span`,{className:`label-text text-sm font-medium`,children:`Project`}),(0,H.jsx)(`input`,{type:`text`,className:`input input-bordered w-full text-base`,placeholder:n||`Enter your project name`,value:e,onChange:e=>t(e.target.value),onBlur:n=>{let r=m(n.target.value);r!==e&&t(r)}})]}),i&&(0,H.jsxs)(`div`,{className:`text-xs text-base-content/50 break-all`,children:[`Workspace: `,i]}),!n&&!p&&(0,H.jsxs)(`div`,{className:`alert alert-warning text-sm`,children:[(0,H.jsx)(x,{className:`size-4 shrink-0`}),(0,H.jsx)(`span`,{children:`We could not detect a project name from the current directory. Enter one to continue.`})]}),(0,H.jsxs)(`div`,{className:`rounded-xl border border-base-300/70 bg-base-100 px-4 py-3`,children:[(0,H.jsx)(`div`,{className:`text-xs uppercase tracking-[0.2em] text-base-content/40`,children:`Queue title preview`}),(0,H.jsx)(`div`,{className:`mt-1.5 text-base font-semibold tracking-tight break-words`,children:h})]})]}),(0,H.jsx)(ge,{currentBranch:a,onBranchCreated:o}),(0,H.jsx)(_e,{mergeMode:s,setMergeMode:c,prBaseBranch:l,setPrBaseBranch:u,currentBranch:a}),(0,H.jsx)(Q,{testCommand:d,setTestCommand:f})]})}var ye={planner:`plan`,executor:`execute`,reviewer:`review`};function be({options:e,value:t,onChange:n}){return(0,H.jsx)(`div`,{className:`flex gap-1 flex-wrap`,children:e.map(e=>{let r=e.value===t,i=e.icon;return(0,H.jsxs)(`button`,{type:`button`,onClick:()=>n(e.value),className:`flex items-center gap-1 px-2.5 py-1 rounded-full text-[11px] font-medium border transition-all ${r?`${e.color} border-current bg-base-300`:`text-base-content/35 border-base-content/10 hover:border-base-content/30 hover:text-base-content/60`}`,children:[(0,H.jsx)(i,{className:`size-2.5`}),e.label]},e.value)})})}function xe({providers:e,providersLoading:t,pipeline:n,setPipeline:r,efforts:i,setEfforts:a,models:o,setModels:c,modelsByProvider:l}){let u=Array.isArray(e)?e:[],d=u.filter(e=>e.available!==!1);return(0,V.useEffect)(()=>{for(let e of[`planner`,`executor`,`reviewer`]){let t=q(e,n),r=i[e];r&&!t.some(e=>e.value===r)&&a(t=>({...t,[e]:`high`}))}},[n,i,a]),(0,H.jsxs)(`div`,{className:`flex flex-col gap-5 w-full max-w-lg`,children:[(0,H.jsxs)(`div`,{className:`text-center`,children:[(0,H.jsx)(z,{className:`size-9 text-primary mx-auto mb-2`}),(0,H.jsx)(`h2`,{className:`text-2xl font-bold`,children:`Agent Pipeline`}),(0,H.jsx)(`p`,{className:`text-sm text-base-content/50 mt-1`,children:`Configure which CLI and reasoning depth runs each stage`})]}),t?(0,H.jsxs)(`div`,{className:`flex flex-col items-center gap-3 py-10`,children:[(0,H.jsx)(j,{className:`size-7 text-primary animate-spin`}),(0,H.jsx)(`p`,{className:`text-sm text-base-content/50`,children:`Detecting available CLIs…`})]}):d.length===0?(0,H.jsx)(`div`,{className:`alert alert-warning text-sm`,children:`No providers detected. Install claude, codex, or gemini CLI first.`}):(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(`div`,{className:`flex flex-wrap gap-2 justify-center`,children:u.map(e=>{let t=e.id||e.name||e,n=e.available!==!1;return(0,H.jsxs)(`span`,{className:`badge gap-1.5 badge-sm ${n?`badge-success`:`badge-ghost opacity-40`}`,children:[n?(0,H.jsx)(te,{className:`size-3`}):(0,H.jsx)(s,{className:`size-3`}),(0,H.jsx)(`span`,{className:`font-mono`,children:t}),e.path&&(0,H.jsx)(`span`,{className:`opacity-50 text-[9px] hidden sm:inline`,children:e.path})]},t)})}),(0,H.jsx)(`div`,{className:`flex flex-col`,children:Y.map((e,t)=>{let s=e.icon,u=n[e.role]||d[0]?.id||d[0]?.name||``,f=ye[e.role],p=o?.[f]||``,m=l?.[u]||[],h=q(e.role,n),_=i?.[e.role]||`high`;return(0,H.jsxs)(`div`,{children:[t>0&&(0,H.jsx)(`div`,{className:`flex justify-center py-1.5 text-base-content/20`,children:(0,H.jsx)(g,{className:`size-4`})}),(0,H.jsx)(`div`,{className:`bg-base-200 rounded-xl p-4`,children:(0,H.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,H.jsx)(`div`,{className:`size-8 rounded-lg flex items-center justify-center bg-base-300 shrink-0 ${e.color}`,children:(0,H.jsx)(s,{className:`size-4`})}),(0,H.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,H.jsx)(`span`,{className:`font-semibold text-sm`,children:e.label}),(0,H.jsx)(`p`,{className:`text-[11px] text-base-content/40 leading-tight mt-0.5 truncate`,children:e.description})]}),(0,H.jsx)(`select`,{className:`select select-sm select-bordered w-28 shrink-0`,value:u,onChange:t=>{let n=t.target.value;r(t=>({...t,[e.role]:n}));let i=l?.[n]?.[0]?.id||``;c(e=>({...e,[f]:i}))},children:d.map(e=>{let t=e.id||e.name||e;return(0,H.jsx)(`option`,{value:t,children:t},t)})})]}),(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(`span`,{className:`text-[10px] text-base-content/40 shrink-0 w-10`,children:`Effort`}),(0,H.jsx)(be,{options:h,value:_,onChange:t=>a(n=>({...n,[e.role]:t}))})]}),m.length>0&&(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(`span`,{className:`text-[10px] text-base-content/40 shrink-0 w-10`,children:`Model`}),(0,H.jsx)(`select`,{className:`select select-xs select-bordered flex-1`,value:p,onChange:e=>c(t=>({...t,[f]:e.target.value})),children:m.map(e=>(0,H.jsx)(`option`,{value:e.id,children:e.label||e.id},e.id))})]})]})})]},e.role)})}),(0,H.jsx)(`p`,{className:`text-[11px] text-base-content/35 text-center`,children:`Pipeline runs top to bottom: plan → execute → review`})]})]})}function Se({selectedAgents:e,setSelectedAgents:t,existingAgents:n}){let[r,i]=(0,V.useState)([]),[a,o]=(0,V.useState)(!1),s=(0,V.useRef)(!1),[u,f]=(0,V.useState)([]),[p,m]=(0,V.useState)(!1),[h,g]=(0,V.useState)(``),[_,v]=(0,V.useState)(()=>new Set),[y,b]=(0,V.useState)({}),x=(0,V.useRef)(!1),[S,C]=(0,V.useState)(``),w=(0,V.useCallback)(()=>d.get(`/catalog/agents`).catch(()=>({agents:[]})).then(e=>{let t=e?.agents||[];return i(t),t}),[]);(0,V.useEffect)(()=>{s.current||(s.current=!0,o(!0),w().then(r=>{let i=new Set((n||[]).map(e=>e.name)),a=r.filter(e=>!i.has(e.name)).map(e=>e.name);a.length>0&&e.length===0&&t(a)}).finally(()=>o(!1)))},[]);let T=(0,V.useCallback)(()=>(g(``),m(!0),d.get(`/reference-repositories`).then(e=>{f(e?.repositories||[])}).catch(e=>{let t=e?.message||`Failed to load reference repositories.`;t.toLowerCase().includes(`route not found`)?g(`Backend route not loaded. Start Fifony with --dev (or run pnpm build:server) and retry.`):g(t)}).finally(()=>m(!1))),[]);(0,V.useEffect)(()=>{x.current||(x.current=!0,T())},[T]);let E=(0,V.useMemo)(()=>new Set((n||[]).map(e=>e.name)),[n]),D=(0,V.useMemo)(()=>{let e=S.trim().toLowerCase();return e?r.filter(t=>[t?.name,t?.displayName,t?.description].filter(Boolean).join(` `).toLowerCase().includes(e)):r},[S,r]),O=(0,V.useCallback)(e=>{t(t=>t.includes(e)?t.filter(t=>t!==e):[...t,e])},[t]),A=(0,V.useCallback)(()=>{t(r.filter(e=>!E.has(e.name)).map(e=>e.name))},[r,E,t]),ee=(0,V.useCallback)(()=>t([]),[t]),N=(0,V.useCallback)(async e=>{v(t=>new Set([...t,e])),b(t=>({...t,[e]:``}));try{let t=((await d.post(`/reference-repositories/sync`,{repository:e}))?.results||[]).find(t=>t.id===e);if(t?.action===`failed`){b(n=>({...n,[e]:t.message||`Sync failed.`}));return}await d.post(`/reference-repositories/import`,{repository:e,kind:`agents`,global:!1}),await Promise.all([T(),w()]),b(t=>({...t,[e]:`Synced & imported.`}))}catch(t){b(n=>({...n,[e]:t?.message||`Failed.`}))}finally{v(t=>{let n=new Set(t);return n.delete(e),n})}},[T,w]);return a?(0,H.jsxs)(`div`,{className:`flex flex-col items-center gap-3 py-12`,children:[(0,H.jsx)(j,{className:`size-8 text-primary animate-spin`}),(0,H.jsx)(`p`,{className:`text-sm text-base-content/50`,children:`Loading catalog...`})]}):(0,H.jsxs)(`div`,{className:`flex flex-col gap-6 stagger-children`,children:[(0,H.jsxs)(`div`,{className:`text-center`,children:[(0,H.jsx)(c,{className:`size-10 text-primary mx-auto mb-3`}),(0,H.jsx)(`h2`,{className:`text-2xl font-bold`,children:`Agents`}),(0,H.jsx)(`p`,{className:`text-base-content/60 mt-1`,children:`Choose which agents to install`})]}),(0,H.jsx)(`div`,{className:`card bg-base-200`,children:(0,H.jsxs)(`div`,{className:`card-body gap-3 p-4`,children:[(0,H.jsx)(`h3`,{className:`font-semibold text-sm`,children:`Sources`}),h&&(0,H.jsx)(`div`,{className:`alert alert-warning text-xs`,children:h}),p?(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-base-content/60`,children:[(0,H.jsx)(j,{className:`size-3 animate-spin`}),` Loading...`]}):(0,H.jsx)(`div`,{className:`grid grid-cols-2 xl:grid-cols-4 gap-2`,children:u.map(e=>{let t=_.has(e.id),n=e?.artifactCounts??null,r=e?.present&&e?.synced;return(0,H.jsxs)(`div`,{className:`rounded-lg border border-base-300/70 bg-base-100 p-2 flex flex-col gap-1.5`,children:[(0,H.jsx)(`div`,{className:`font-medium text-xs truncate`,children:e.name}),r&&n?(0,H.jsxs)(`div`,{className:`text-[11px] text-base-content/60`,children:[n.agents,` agents`]}):(0,H.jsx)(`span`,{className:`badge badge-xs badge-warning`,children:`Not synced`}),y[e.id]&&(0,H.jsx)(`p`,{className:`text-[11px] text-base-content/60 truncate`,children:y[e.id]}),(0,H.jsxs)(`button`,{className:`btn btn-xs btn-outline gap-1 mt-auto`,onClick:()=>N(e.id),disabled:t,children:[t?(0,H.jsx)(j,{className:`size-3 animate-spin`}):(0,H.jsx)(M,{className:`size-3`}),t?`Syncing…`:r?`Re-sync`:`Sync`]})]},e.id)})})]})}),(0,H.jsxs)(`div`,{className:`space-y-2`,children:[(0,H.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,H.jsxs)(`h3`,{className:`font-semibold text-sm flex items-center gap-2`,children:[(0,H.jsx)(c,{className:`size-4 opacity-50`}),`Agents (`,r.length,`)`]}),(0,H.jsxs)(`div`,{className:`flex gap-1`,children:[(0,H.jsx)(`button`,{className:`btn btn-xs btn-ghost`,onClick:A,children:`Select All`}),(0,H.jsx)(`button`,{className:`btn btn-xs btn-ghost`,onClick:ee,children:`None`})]})]}),(0,H.jsxs)(`label`,{className:`input input-bordered input-sm flex items-center gap-2`,children:[(0,H.jsx)(k,{className:`size-4 opacity-60`}),(0,H.jsx)(`input`,{type:`text`,className:`grow`,placeholder:`Search agents...`,value:S,onChange:e=>C(e.target.value)})]}),D.length===0&&r.length>0&&(0,H.jsx)(`div`,{className:`text-sm text-base-content/60`,children:`No agents match your search.`}),(0,H.jsx)(`div`,{className:`space-y-1 pt-1`,children:D.map(t=>{let n=E.has(t.name),r=n||e.includes(t.name);return(0,H.jsx)(`button`,{className:`w-full rounded-md border border-transparent px-2 py-2 text-left transition-all ${n?`opacity-70 bg-base-100/40`:`hover:bg-base-100`} ${r&&!n?`ring-1 ring-primary ring-offset-1 ring-offset-base-200`:``}`,onClick:()=>!n&&O(t.name),disabled:n,children:(0,H.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,H.jsx)(`span`,{className:`mt-0.5 text-base`,children:t.emoji||`🤖`}),(0,H.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(`span`,{className:`font-medium text-sm truncate`,children:t.displayName||t.name}),t.source&&(0,H.jsx)(`span`,{className:`badge badge-xs badge-ghost shrink-0`,children:t.source}),n?(0,H.jsxs)(`span`,{className:`badge badge-xs badge-success gap-1 shrink-0`,children:[(0,H.jsx)(l,{className:`size-3`}),` Installed`]}):(0,H.jsx)(`input`,{type:`checkbox`,className:`checkbox checkbox-primary checkbox-sm self-start mt-0.5 shrink-0`,checked:r,readOnly:!0,tabIndex:-1})]}),t.description&&(0,H.jsx)(`p`,{className:`text-xs text-base-content/60 mt-1 truncate`,children:t.description})]})]})},t.name)})})]}),r.length===0&&(0,H.jsx)(`div`,{className:`alert alert-info text-sm`,children:`No agents found in the catalog. Sync a source above or add them later from the settings page.`})]})}var Ce={auto:{bg:null,label:`Auto`},light:{bg:`#ffffff`,accent:`#7c3aed`},dark:{bg:`#1d232a`,accent:`#661ae6`},black:{bg:`#000000`,accent:`#ffffff`},cupcake:{bg:`#faf7f5`,accent:`#ef9fbc`},night:{bg:`#0f172a`,accent:`#38bdf8`},sunset:{bg:`#1a1019`,accent:`#ff865b`}};function we({theme:e,selected:t,onClick:n}){let r=Ce[e.value];return(0,H.jsxs)(`button`,{onClick:n,title:e.label,className:`flex flex-col items-center gap-1.5 group focus:outline-none`,children:[(0,H.jsx)(`div`,{className:`w-10 h-10 rounded-xl border-2 transition-all overflow-hidden flex-shrink-0 ${t?`border-primary ring-2 ring-primary ring-offset-2 ring-offset-base-200 scale-110`:`border-base-300 group-hover:border-base-content/30 group-hover:scale-105`}`,style:r.bg?{background:r.bg}:void 0,children:r.bg?(0,H.jsxs)(`div`,{className:`w-full h-full flex flex-col`,children:[(0,H.jsx)(`div`,{className:`flex-1`,style:{background:r.bg}}),(0,H.jsx)(`div`,{className:`h-3 w-full`,style:{background:r.accent}})]}):(0,H.jsxs)(`div`,{className:`w-full h-full flex`,children:[(0,H.jsx)(`div`,{className:`flex-1 bg-white`}),(0,H.jsx)(`div`,{className:`flex-1 bg-neutral`})]})}),(0,H.jsx)(`span`,{className:`text-xs font-medium transition-colors ${t?`text-primary`:`text-base-content/50 group-hover:text-base-content/80`}`,children:e.label})]})}function Te({concurrency:e,setConcurrency:t,selectedTheme:n,setSelectedTheme:r}){let i=Number.isFinite(e)?Math.max(1,Math.min(10,e)):1;return(0,H.jsxs)(`div`,{className:`flex flex-col gap-6 stagger-children`,children:[(0,H.jsxs)(`div`,{className:`text-center`,children:[(0,H.jsx)(D,{className:`size-10 text-primary mx-auto mb-3`}),(0,H.jsx)(`h2`,{className:`text-2xl font-bold`,children:`Workers & Theme`}),(0,H.jsx)(`p`,{className:`text-base-content/60 mt-1 text-sm`,children:`Configure parallel workers and visual theme`})]}),(0,H.jsx)(`div`,{className:`card bg-base-200`,children:(0,H.jsxs)(`div`,{className:`card-body p-5 gap-3`,children:[(0,H.jsxs)(`h3`,{className:`font-semibold text-sm flex items-center gap-2`,children:[(0,H.jsx)(D,{className:`size-4 opacity-50`}),`Worker Concurrency`]}),(0,H.jsxs)(`p`,{className:`text-xs text-base-content/60`,children:[`How many agents can work in parallel (`,i,` worker`,i===1?``:`s`,`)`]}),(0,H.jsxs)(`div`,{className:`w-full max-w-xs`,children:[(0,H.jsx)(`input`,{type:`range`,min:1,max:10,step:1,value:i,onChange:e=>t(Math.round(Number(e.target.value))),"aria-label":`Number of parallel workers`,className:`range range-primary range-sm w-full`}),(0,H.jsx)(`div`,{className:`flex justify-between px-2.5 mt-2 text-xs`,children:Array.from({length:10},(e,t)=>(0,H.jsx)(`span`,{children:`|`},t))}),(0,H.jsx)(`div`,{className:`flex justify-between px-2.5 mt-2 text-xs`,children:Array.from({length:10},(e,t)=>(0,H.jsx)(`span`,{children:t+1},t))})]}),(0,H.jsxs)(`p`,{className:`text-xs text-base-content/50 bg-base-100 rounded-lg px-3 py-2 mt-1`,children:[(0,H.jsx)(`span`,{className:`font-medium text-base-content/70`,children:`Tip:`}),` 2–4 workers is recommended for most projects. More workers consume more API quota and may hit rate limits.`]})]})}),(0,H.jsx)(`div`,{className:`card bg-base-200`,children:(0,H.jsxs)(`div`,{className:`card-body p-5 gap-4`,children:[(0,H.jsxs)(`h3`,{className:`font-semibold text-sm flex items-center gap-2`,children:[(0,H.jsx)(w,{className:`size-4 opacity-50`}),`Theme`]}),(0,H.jsx)(`div`,{className:`flex flex-wrap gap-5 justify-center py-1`,children:J.map(e=>(0,H.jsx)(we,{theme:e,selected:n===e.value,onClick:()=>r(e.value)},e.value))})]})})]})}function Ee({config:e,launching:t}){return(0,H.jsxs)(`div`,{className:`flex flex-col items-center text-center gap-6 stagger-children py-4`,children:[(0,H.jsx)(`div`,{className:`animate-bounce-in`,children:(0,H.jsx)(z,{className:`size-16 sm:size-20 text-primary mx-auto`})}),(0,H.jsx)(`h2`,{className:`text-2xl sm:text-3xl font-bold`,children:`You're All Set!`}),(0,H.jsx)(`p`,{className:`text-base-content/60 max-w-md`,children:`Here's a summary of your configuration. Hit launch when you're ready.`}),(0,H.jsx)(`div`,{className:`card bg-base-200 w-full max-w-sm`,children:(0,H.jsxs)(`div`,{className:`card-body p-4 gap-2 text-sm text-left`,children:[(0,H.jsxs)(`div`,{className:`flex justify-between gap-4`,children:[(0,H.jsx)(`span`,{className:`text-base-content/60`,children:`Queue title`}),(0,H.jsx)(`span`,{className:`font-semibold text-right break-words`,children:e.queueTitle||`fifony`})]}),(0,H.jsx)(`div`,{className:`divider my-0`}),(0,H.jsxs)(`div`,{className:`flex justify-between`,children:[(0,H.jsx)(`span`,{className:`text-base-content/60`,children:`Pipeline`}),(0,H.jsxs)(`span`,{className:`font-semibold capitalize text-xs font-mono`,children:[e.pipeline?.planner||`?`,` → `,e.pipeline?.executor||`?`,` → `,e.pipeline?.reviewer||`?`]})]}),(0,H.jsx)(`div`,{className:`divider my-0`}),(0,H.jsxs)(`div`,{className:`flex justify-between`,children:[(0,H.jsx)(`span`,{className:`text-base-content/60`,children:`Domains`}),(0,H.jsx)(`span`,{className:`font-semibold`,children:e.domains?.length>0?e.domains.length+` selected`:`none`})]}),(0,H.jsx)(`div`,{className:`divider my-0`}),(0,H.jsxs)(`div`,{className:`flex justify-between`,children:[(0,H.jsx)(`span`,{className:`text-base-content/60`,children:`Agents`}),(0,H.jsxs)(`span`,{className:`font-semibold`,children:[e.agents?.length||0,` to install`]})]}),(0,H.jsx)(`div`,{className:`divider my-0`}),(0,H.jsxs)(`div`,{className:`flex justify-between`,children:[(0,H.jsx)(`span`,{className:`text-base-content/60`,children:`Skills`}),(0,H.jsxs)(`span`,{className:`font-semibold`,children:[e.skills?.length||0,` to install`]})]}),(0,H.jsx)(`div`,{className:`divider my-0`}),(0,H.jsxs)(`div`,{className:`flex justify-between`,children:[(0,H.jsx)(`span`,{className:`text-base-content/60`,children:`Plan`}),(0,H.jsx)(`span`,{className:`font-semibold capitalize`,children:e.efforts.planner})]}),(0,H.jsx)(`div`,{className:`divider my-0`}),(0,H.jsxs)(`div`,{className:`flex justify-between`,children:[(0,H.jsx)(`span`,{className:`text-base-content/60`,children:`Execute`}),(0,H.jsx)(`span`,{className:`font-semibold capitalize`,children:e.efforts.executor})]}),(0,H.jsx)(`div`,{className:`divider my-0`}),(0,H.jsxs)(`div`,{className:`flex justify-between`,children:[(0,H.jsx)(`span`,{className:`text-base-content/60`,children:`Review`}),(0,H.jsx)(`span`,{className:`font-semibold capitalize`,children:e.efforts.reviewer})]}),(0,H.jsx)(`div`,{className:`divider my-0`}),(0,H.jsxs)(`div`,{className:`flex justify-between`,children:[(0,H.jsx)(`span`,{className:`text-base-content/60`,children:`Workers`}),(0,H.jsx)(`span`,{className:`font-semibold`,children:e.concurrency})]}),(0,H.jsx)(`div`,{className:`divider my-0`}),(0,H.jsxs)(`div`,{className:`flex justify-between`,children:[(0,H.jsx)(`span`,{className:`text-base-content/60`,children:`Theme`}),(0,H.jsx)(`span`,{className:`font-semibold capitalize`,children:e.theme})]})]})}),t&&(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-base-content/50`,children:[(0,H.jsx)(j,{className:`size-4 animate-spin`}),`Saving configuration & installing agents...`]})]})}function De({onComplete:e}){let t=r(),n=o(),i=f(n.data),[s,c]=(0,V.useState)(0),[l,g]=(0,V.useState)(`forward`),[v,y]=(0,V.useState)(!1),[b,x]=(0,V.useState)(null),S=(0,V.useRef)(!1),C=(0,V.useRef)(!1),[w,T]=(0,V.useState)({planner:``,executor:``,reviewer:``}),[E,D]=(0,V.useState)(()=>ce(null)),[k,A]=(0,V.useState)(3),[j,M]=(0,V.useState)(`auto`),[N,te]=(0,V.useState)(``),[ne,P]=(0,V.useState)(`missing`),[F,I]=(0,V.useState)(null),[L,re]=(0,V.useState)([]),[R,z]=(0,V.useState)([]),[B,U]=(0,V.useState)(`local`),[W,G]=(0,V.useState)(``),[K,se]=(0,V.useState)(``),q=oe(),J=ae()[s]||``,[Y,Z]=(0,V.useState)(null),[me,he]=(0,V.useState)(!1),[ge,_e]=(0,V.useState)({}),[Q,ye]=(0,V.useState)({plan:``,execute:``,review:``}),[be,Ce]=(0,V.useState)(``),[we,De]=(0,V.useState)(``);(0,V.useEffect)(()=>{d.get(`/state`).then(e=>{I(e||{}),Ce(e?.sourceRepoUrl||e?.config?.sourceRepo||``),De(e?.config?.defaultBranch||``)}).catch(()=>{I({})})},[]),(0,V.useEffect)(()=>{if(S.current||n.isLoading)return;S.current=!0;let e=u(i,`runtime.pipeline`,null),t=u(i,`runtime.workflowConfig`,null),r=u(i,`runtime.defaultEffort`,null),a=u(i,`ui.theme`,`auto`),o=u(i,`runtime.workerConcurrency`,3);if(Array.isArray(e)&&e.length>0){let t=Object.fromEntries(e.map(e=>[e.role,e.provider]));T({planner:t.planner||``,executor:t.executor||``,reviewer:t.reviewer||``})}t&&typeof t==`object`&&ye({plan:t.plan?.model||``,execute:t.execute?.model||``,review:t.review?.model||``}),D(ce(r)),typeof a==`string`&&a.trim()&&M(a);let s=Number.parseInt(String(o??2),10);Number.isFinite(s)&&A(Math.min(10,Math.max(1,s)));let c=u(i,`runtime.mergeMode`,`local`);(c===`local`||c===`push-pr`)&&U(c);let l=u(i,`runtime.prBaseBranch`,``);typeof l==`string`&&G(l);let d=u(i,`runtime.testCommand`,``);typeof d==`string`&&se(d)},[i,n.isLoading]),(0,V.useEffect)(()=>{if(C.current||n.isLoading||F===null)return;C.current=!0;let e=h(i,F);te(e.projectName),P(e.source)},[F,i,n.isLoading]);let Oe=(0,V.useCallback)(e=>{te(e),P(`manual`)},[]),$=m(N),ke=O($);(0,V.useEffect)(()=>{document.title=O($||F?.detectedProjectName||F?.projectName||``)},[$,F]),(0,V.useEffect)(()=>{s>=1&&Y===null&&(he(!0),Promise.all([d.get(`/providers`),d.get(`/config/workflow?details=1`).catch(()=>null)]).then(([e,t])=>{let n=Array.isArray(e)?e:e?.providers||[];Z(n);let r=t?.models||{};_e(r);let i=n.filter(e=>e.available!==!1),a=i[0]?.id||i[0]?.name||``,o=i.find(e=>(e.id||e.name)===`claude`),s=a,c=o?`claude`:s,l={planner:c,executor:s,reviewer:c};T(e=>({planner:e.planner||l.planner,executor:e.executor||l.executor,reviewer:e.reviewer||l.reviewer})),ye(e=>({plan:e.plan||r[c]?.[0]?.id||``,execute:e.execute||r[s]?.[0]?.id||``,review:e.review||r[c]?.[0]?.id||``}))}).catch(()=>{Z([])}).finally(()=>{he(!1)}))},[s,Y]),(0,V.useEffect)(()=>{let e=j===`auto`?window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`:j;document.documentElement.setAttribute(`data-theme`,e)},[j]);let Ae=(0,V.useCallback)(e=>{if(e===`Setup`)$&&X(a,$,`system`).catch(()=>{}),X(`runtime.mergeMode`,B,`runtime`).catch(()=>{}),B===`push-pr`&&W.trim()&&X(`runtime.prBaseBranch`,W.trim(),`runtime`).catch(()=>{}),K.trim()&&X(`runtime.testCommand`,K.trim(),`runtime`).catch(()=>{});else if(e===`Pipeline`){let e=[{provider:w.planner,role:`planner`},{provider:w.executor,role:`executor`},{provider:w.reviewer,role:`reviewer`}];X(`runtime.agentProvider`,w.executor,`runtime`).catch(()=>{}),X(`runtime.pipeline`,e,`runtime`).catch(()=>{}),X(`runtime.defaultEffort`,E,`runtime`).catch(()=>{}),X(`runtime.workflowConfig`,le(w,E,Q),`runtime`).catch(()=>{})}else e===`Preferences`&&(X(`ui.theme`,j,`ui`).catch(()=>{}),d.post(`/config/concurrency`,{concurrency:k}).catch(()=>{}))},[w,E,Q,k,j,$,B,W,K]),je=(0,V.useCallback)(()=>{s<q-1&&(Ae(J),g(`forward`),c(e=>e+1))},[s,q,J,Ae]),Me=(0,V.useCallback)(()=>{s>0&&(g(`backward`),c(e=>e-1))},[s]),Ne=(0,V.useCallback)(async()=>{if($){y(!0);try{let n=[X(a,$,`system`),X(`ui.theme`,j,`ui`),X(`ui.onboarding.completed`,!0,`ui`)],r=[{provider:w.planner,role:`planner`},{provider:w.executor,role:`executor`},{provider:w.reviewer,role:`reviewer`}];n.push(X(`runtime.agentProvider`,w.executor,`runtime`)),n.push(X(`runtime.pipeline`,r,`runtime`)),n.push(X(`runtime.defaultEffort`,E,`runtime`)),n.push(X(`runtime.workflowConfig`,le(w,E,Q),`runtime`)),n.push(d.post(`/config/concurrency`,{concurrency:k})),n.push(X(`runtime.mergeMode`,B,`runtime`)),B===`push-pr`&&W.trim()&&n.push(X(`runtime.prBaseBranch`,W.trim(),`runtime`)),K.trim()&&n.push(X(`runtime.testCommand`,K.trim(),`runtime`)),L.length>0&&n.push(d.post(`/install/agents`,{agents:L})),R.length>0&&n.push(d.post(`/install/skills`,{skills:R})),await Promise.allSettled(n),t.setQueryData(_,e=>p(e,{id:a,scope:`system`,value:$,source:`user`,updatedAt:new Date().toISOString()})),t.setQueryData(_,e=>p(e,{id:`ui.onboarding.completed`,scope:`ui`,value:!0,source:`user`,updatedAt:new Date().toISOString()})),x({x:window.innerWidth/2,y:window.innerHeight/3}),setTimeout(()=>{t.invalidateQueries({queryKey:_}),e?.()},1200)}catch{t.setQueryData(_,e=>p(e,{id:a,scope:`system`,value:$,source:`user`,updatedAt:new Date().toISOString()})),t.setQueryData(_,e=>p(e,{id:`ui.onboarding.completed`,scope:`ui`,value:!0,source:`user`,updatedAt:new Date().toISOString()})),await X(`ui.onboarding.completed`,!0,`ui`).catch(()=>{}),t.invalidateQueries({queryKey:_}),e?.()}}},[$,w,E,Q,k,j,L,R,B,W,K,t,e]),Pe=J===`Welcome`||J===`Setup`&&!!$||J===`Pipeline`&&(w.executor||me)||J===`Agents & Skills`||J===`Preferences`||J===`Launch`,Fe=[],Ie=[],Le={projectName:$,queueTitle:ke,pipeline:w,efforts:E,concurrency:k,theme:j,agents:L,skills:R};return(0,H.jsxs)(`div`,{className:`fixed inset-0 z-50 bg-base-100 flex flex-col overflow-hidden`,children:[s===0&&(0,H.jsx)(ie,{}),b&&(0,H.jsx)(ee,{x:b.x,y:b.y,active:!0,onDone:()=>x(null)}),s>0&&(0,H.jsx)(`div`,{className:`relative z-10 pt-6 pb-2 px-4 flex justify-center`,children:(0,H.jsx)(ue,{current:s})}),(0,H.jsx)(`div`,{className:`relative z-10 flex-1 flex flex-col items-center justify-start px-4 py-6 overflow-y-auto`,children:(0,H.jsxs)(de,{direction:l,stepKey:s,center:J===`Welcome`||J===`Setup`||J===`Pipeline`||J===`Launch`,children:[J===`Welcome`&&(0,H.jsx)(pe,{workspacePath:be,onGetStarted:je}),J===`Setup`&&(0,H.jsx)(ve,{projectName:N,setProjectName:Oe,detectedProjectName:F?.detectedProjectName||``,projectSource:ne,workspacePath:be,currentBranch:we,onBranchCreated:e=>{De(e),W||G(e)},mergeMode:B,setMergeMode:U,prBaseBranch:W,setPrBaseBranch:G,testCommand:K,setTestCommand:se}),J===`Pipeline`&&(0,H.jsx)(xe,{providers:Y||[],providersLoading:me,pipeline:w,setPipeline:T,efforts:E,setEfforts:D,models:Q,setModels:ye,modelsByProvider:ge}),J===`Agents & Skills`&&(0,H.jsx)(Se,{selectedAgents:L,setSelectedAgents:re,selectedSkills:R,setSelectedSkills:z,existingAgents:Fe,existingSkills:Ie}),J===`Preferences`&&(0,H.jsx)(Te,{concurrency:k,setConcurrency:A,selectedTheme:j,setSelectedTheme:M}),J===`Launch`&&(0,H.jsx)(Ee,{config:Le,launching:v})]})}),(0,H.jsx)(fe,{step:s,stepCount:q,stepName:J,canProceed:Pe,launching:v,onBack:Me,onNext:je,onLaunch:Ne})]})}export{De as default};
|