panopticon-cli 0.4.33 → 0.5.1
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 +96 -210
- package/dist/{agents-VLK4BMVA.js → agents-5OPQKM5K.js} +6 -5
- package/dist/{chunk-OMNXYPXC.js → chunk-2V4NF7J2.js} +14 -1
- package/dist/chunk-2V4NF7J2.js.map +1 -0
- package/dist/{chunk-XKT5MHPT.js → chunk-4YSYJ4HM.js} +2 -2
- package/dist/{chunk-XFR2DLMR.js → chunk-76F6DSVS.js} +49 -10
- package/dist/chunk-76F6DSVS.js.map +1 -0
- package/dist/{chunk-PI7Y3PSN.js → chunk-F5555J3A.js} +42 -6
- package/dist/chunk-F5555J3A.js.map +1 -0
- package/dist/{chunk-KJ2TRXNK.js → chunk-FTCPTHIJ.js} +47 -420
- package/dist/chunk-FTCPTHIJ.js.map +1 -0
- package/dist/chunk-HJSM6E6U.js +1038 -0
- package/dist/chunk-HJSM6E6U.js.map +1 -0
- package/dist/{chunk-RBUO57TC.js → chunk-NLQRED36.js} +3 -3
- package/dist/chunk-NLQRED36.js.map +1 -0
- package/dist/{chunk-ASY7T35E.js → chunk-OWHXCGVO.js} +245 -90
- package/dist/chunk-OWHXCGVO.js.map +1 -0
- package/dist/{chunk-BKCWRMUX.js → chunk-VHKSS7QX.js} +106 -11
- package/dist/chunk-VHKSS7QX.js.map +1 -0
- package/dist/{chunk-GFP3PIPB.js → chunk-YGJ54GW2.js} +1 -1
- package/dist/chunk-YGJ54GW2.js.map +1 -0
- package/dist/cli/index.js +1521 -935
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/prompts/work-agent.md +2 -0
- package/dist/dashboard/public/assets/index-Ce6q21Fm.js +743 -0
- package/dist/dashboard/public/assets/{index-UjZq6ykz.css → index-NzpI0ItZ.css} +1 -1
- package/dist/dashboard/public/index.html +2 -2
- package/dist/dashboard/server.js +4274 -2320
- package/dist/{feedback-writer-LVZ5TFYZ.js → feedback-writer-VRMMWWTW.js} +2 -2
- package/dist/git-utils-I2UDKNZH.js +131 -0
- package/dist/git-utils-I2UDKNZH.js.map +1 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/{projects-JEIVIYC6.js → projects-CFX3RTDL.js} +4 -2
- package/dist/{remote-workspace-AHVHQEES.js → remote-workspace-7FPGF2RM.js} +2 -2
- package/dist/{review-status-EPFG4XM7.js → review-status-TDPSOU5J.js} +2 -2
- package/dist/{specialist-context-T3NBMCIE.js → specialist-context-WGUUYDWY.js} +5 -5
- package/dist/{specialist-logs-CVKD3YJ3.js → specialist-logs-XJB5TCKJ.js} +5 -5
- package/dist/{specialists-TKAP6T6Z.js → specialists-5LBRHYFA.js} +5 -5
- package/dist/{traefik-QX4ZV4YG.js → traefik-WFMQX2LY.js} +3 -3
- package/dist/{workspace-manager-KLHUCIZV.js → workspace-manager-E434Z45T.js} +2 -2
- package/package.json +1 -1
- package/scripts/record-cost-event.js +5 -5
- package/scripts/stop-hook +7 -0
- package/scripts/work-agent-stop-hook +137 -0
- package/skills/myn-standards/SKILL.md +351 -0
- package/skills/pan-new-project/SKILL.md +304 -0
- package/skills/write-spec/SKILL.md +138 -0
- package/dist/chunk-7XNJJBH6.js +0 -538
- package/dist/chunk-7XNJJBH6.js.map +0 -1
- package/dist/chunk-ASY7T35E.js.map +0 -1
- package/dist/chunk-BKCWRMUX.js.map +0 -1
- package/dist/chunk-GFP3PIPB.js.map +0 -1
- package/dist/chunk-KJ2TRXNK.js.map +0 -1
- package/dist/chunk-OMNXYPXC.js.map +0 -1
- package/dist/chunk-PI7Y3PSN.js.map +0 -1
- package/dist/chunk-RBUO57TC.js.map +0 -1
- package/dist/chunk-XFR2DLMR.js.map +0 -1
- package/dist/dashboard/public/assets/index-kAJqtLDO.js +0 -708
- /package/dist/{agents-VLK4BMVA.js.map → agents-5OPQKM5K.js.map} +0 -0
- /package/dist/{chunk-XKT5MHPT.js.map → chunk-4YSYJ4HM.js.map} +0 -0
- /package/dist/{feedback-writer-LVZ5TFYZ.js.map → feedback-writer-VRMMWWTW.js.map} +0 -0
- /package/dist/{projects-JEIVIYC6.js.map → projects-CFX3RTDL.js.map} +0 -0
- /package/dist/{remote-workspace-AHVHQEES.js.map → remote-workspace-7FPGF2RM.js.map} +0 -0
- /package/dist/{review-status-EPFG4XM7.js.map → review-status-TDPSOU5J.js.map} +0 -0
- /package/dist/{specialist-context-T3NBMCIE.js.map → specialist-context-WGUUYDWY.js.map} +0 -0
- /package/dist/{specialist-logs-CVKD3YJ3.js.map → specialist-logs-XJB5TCKJ.js.map} +0 -0
- /package/dist/{specialists-TKAP6T6Z.js.map → specialists-5LBRHYFA.js.map} +0 -0
- /package/dist/{traefik-QX4ZV4YG.js.map → traefik-WFMQX2LY.js.map} +0 -0
- /package/dist/{workspace-manager-KLHUCIZV.js.map → workspace-manager-E434Z45T.js.map} +0 -0
package/README.md
CHANGED
|
@@ -7,64 +7,99 @@
|
|
|
7
7
|
[](https://www.npmjs.com/package/panopticon-cli)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
[](https://nodejs.org/)
|
|
10
|
-
[](https://github.com/eltmon/panopticon/pulls)
|
|
10
|
+
[](https://github.com/eltmon/panopticon-cli/pulls)
|
|
11
11
|
|
|
12
12
|
> *"The Panopticon had six sides, one for each of the Founders of Gallifrey..."*
|
|
13
|
+
>
|
|
14
|
+
> — Classic Doctor Who. The Panopticon was the great hall at the heart of the Time Lord Citadel, where all could be observed. We liked the metaphor.
|
|
15
|
+
|
|
16
|
+
Spawn AI agents from a dashboard. Route tasks to the right model. Review, test, and merge automatically.
|
|
13
17
|
|
|
14
|
-
<img src="docs/
|
|
18
|
+
<img src="docs/screenshot-board.png" alt="Panopticon Kanban Board" width="800" />
|
|
15
19
|
|
|
16
20
|
</div>
|
|
17
21
|
|
|
18
22
|
---
|
|
19
23
|
|
|
20
|
-
##
|
|
24
|
+
## Why Panopticon?
|
|
25
|
+
|
|
26
|
+
- **Stop babysitting agents.** Spawn them from a dashboard, monitor progress in real time, and let specialists handle code review, testing, and merging.
|
|
27
|
+
- **Use the right model for the job.** Opus for planning, Kimi for implementation, Haiku for quick commands — automatic routing based on task type and required capabilities.
|
|
28
|
+
- **Work survives across sessions.** PRDs, state files, beads, and skills persist context so agents don't start from zero every time.
|
|
29
|
+
- **One skill format, every tool.** Write a SKILL.md once and it works across Claude Code, Codex, Cursor, and Gemini CLI.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## How It Works
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Issue PRD Agent Review Test Merge
|
|
37
|
+
┌──────┐ ┌──────┐ ┌──────────┐ ┌──────┐ ┌──────┐ ┌──────────┐
|
|
38
|
+
│ Task │ ─► │ Plan │ ─► │ Write │ ─► │ Code │ ─► │ Run │ ─► │ PR │
|
|
39
|
+
│ from │ │ with │ │ code in │ │ rev. │ │ test │ │ merged │
|
|
40
|
+
│ any │ │ Opus │ │ isolated │ │ by │ │ by │ │ by │
|
|
41
|
+
│track-│ │ │ │ worktree │ │ spec-│ │ spec-│ │ spec- │
|
|
42
|
+
│ er │ │ │ │ │ │ialist│ │ialist│ │ ialist │
|
|
43
|
+
└──────┘ └──────┘ └──────────┘ └──────┘ └──────┘ └──────────┘
|
|
44
|
+
GitHub Opus Kimi/Sonnet Opus Sonnet Sonnet
|
|
45
|
+
Linear (routed)
|
|
46
|
+
GitLab
|
|
47
|
+
Jira
|
|
48
|
+
Rally
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Create a workspace, and Panopticon handles the rest: planning with Opus, implementation with your configured model, automated code review, test execution, and merge — the only manual step is clicking **MERGE** when you're satisfied.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Key Features
|
|
21
56
|
|
|
22
|
-
|
|
|
23
|
-
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
|
57
|
+
| Feature | Description |
|
|
58
|
+
|:--------|:------------|
|
|
59
|
+
| **Multi-Agent Orchestration** | Spawn and manage AI agents in tmux sessions via dashboard or CLI |
|
|
60
|
+
| **Cloister Lifecycle Manager** | Automatic model routing, stuck detection, cost tracking, and specialist handoffs |
|
|
61
|
+
| **Mission Control** | 11-view dashboard — project tree, activity feed, kanban board, agent status, costs, metrics, and more |
|
|
62
|
+
| **PRD-Driven Workflow** | Opus writes a PRD before implementation starts; agents are blocked without one |
|
|
63
|
+
| **67+ Universal Skills** | Pre-built skills ship out of the box, synced via `pan sync` — one SKILL.md works across all AI tools |
|
|
64
|
+
| **Multi-Tracker Support** | GitHub Issues, Linear, GitLab, Jira, Rally — all from one dashboard |
|
|
65
|
+
| **Multi-Model Routing** | Anthropic, OpenAI, Google, Kimi, Zhipu — route by task type, capability, and budget |
|
|
66
|
+
| **Workspaces** | Git worktree-based feature branches with Docker isolation (local and remote via exe.dev) |
|
|
67
|
+
| **Convoys** | Run parallel agents on related issues with automatic synthesis |
|
|
68
|
+
| **Specialists** | Dedicated review, test, and merge agents — fully automated quality pipeline |
|
|
69
|
+
| **Beads** | Git-backed task tracking that survives context compaction and works offline |
|
|
70
|
+
| **Cost Tracking** | Per-issue, per-stage token costs with dashboard analytics |
|
|
71
|
+
| **Legacy Codebase Support** | AI self-monitoring skills that learn your codebase conventions over time ([details](docs/LEGACY-CODEBASE.md)) |
|
|
72
|
+
|
|
73
|
+
---
|
|
29
74
|
|
|
30
75
|
## Screenshots
|
|
31
76
|
|
|
32
77
|
<div align="center">
|
|
33
78
|
<table>
|
|
34
79
|
<tr>
|
|
35
|
-
<td><img src="docs/
|
|
36
|
-
<td><img src="docs/
|
|
37
|
-
<td><img src="docs/planning-session-active.png" alt="Active Session" width="300" /></td>
|
|
80
|
+
<td><img src="docs/dashboard-overview.png" alt="Mission Control" width="400" /></td>
|
|
81
|
+
<td><img src="docs/screenshot-agents.png" alt="Agent Management" width="400" /></td>
|
|
38
82
|
</tr>
|
|
39
83
|
<tr>
|
|
40
|
-
<td align="center"><em>
|
|
41
|
-
<td align="center"><em>
|
|
42
|
-
|
|
84
|
+
<td align="center"><em>Mission Control — project tree, activity timeline, specialist pipeline</em></td>
|
|
85
|
+
<td align="center"><em>Cloister Deacon, specialist agents, and issue agent management</em></td>
|
|
86
|
+
</tr>
|
|
87
|
+
<tr>
|
|
88
|
+
<td colspan="2"><img src="docs/screenshot-settings.png" alt="Model Routing Settings" width="800" /></td>
|
|
89
|
+
</tr>
|
|
90
|
+
<tr>
|
|
91
|
+
<td colspan="2" align="center"><em>Tracker integration and capability-based model routing</em></td>
|
|
43
92
|
</tr>
|
|
44
93
|
</table>
|
|
45
94
|
</div>
|
|
46
95
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
| Feature | Description |
|
|
50
|
-
|:--------|:------------|
|
|
51
|
-
| **Multi-Agent Orchestration** | Spawn and manage AI agents in tmux sessions via dashboard or CLI |
|
|
52
|
-
| **Cloister Lifecycle Manager** | Automatic model routing, stuck detection, and specialist handoffs |
|
|
53
|
-
| **Universal Skills** | One SKILL.md format works across all supported AI tools |
|
|
54
|
-
| **Workspaces** | Git worktree-based feature branches with Docker isolation |
|
|
55
|
-
| **Convoys** | Run parallel agents on related issues with auto-synthesis |
|
|
56
|
-
| **Specialists** | Dedicated review, test, and merge agents for quality control |
|
|
57
|
-
| **Heartbeat Monitoring** | Real-time agent activity tracking via Claude Code hooks |
|
|
58
|
-
| **Mission Control** | Unified monitoring view — see all active features, agent activity, and planning artifacts at a glance |
|
|
59
|
-
| **Shadow Engineering** | Monitor existing workflows before transitioning to AI-driven development |
|
|
60
|
-
| **Real-Time Dashboard** | Socket.io push with multi-layer caching (in-memory + SQLite) for instant loads |
|
|
61
|
-
| **Legacy Codebase Support** | AI self-monitoring skills that learn from your codebase |
|
|
96
|
+
---
|
|
62
97
|
|
|
63
98
|
## Supported Tools
|
|
64
99
|
|
|
65
100
|
| Tool | Support |
|
|
66
101
|
|:-----|:--------|
|
|
67
|
-
| **Claude Code** | Full support |
|
|
102
|
+
| **Claude Code** | Full support — agent runtime, hooks, skills |
|
|
68
103
|
| **Codex** | Skills sync |
|
|
69
104
|
| **Cursor** | Skills sync |
|
|
70
105
|
| **Gemini CLI** | Skills sync |
|
|
@@ -72,133 +107,7 @@
|
|
|
72
107
|
|
|
73
108
|
---
|
|
74
109
|
|
|
75
|
-
##
|
|
76
|
-
|
|
77
|
-
> **"AI works great on greenfield projects, but it's hopeless on our legacy code."**
|
|
78
|
-
>
|
|
79
|
-
> Sound familiar? Your developers aren't wrong. But they're not stuck, either.
|
|
80
|
-
|
|
81
|
-
### The Problem Every Enterprise Faces
|
|
82
|
-
|
|
83
|
-
AI coding assistants are trained on modern, well-documented open-source code. When they encounter your 15-year-old monolith with:
|
|
84
|
-
|
|
85
|
-
- Mixed naming conventions (some `snake_case`, some `camelCase`, some `SCREAMING_CASE`)
|
|
86
|
-
- Undocumented tribal knowledge ("we never touch the `processUser()` function directly")
|
|
87
|
-
- Schemas that don't match the ORM ("the `accounts` table is actually users")
|
|
88
|
-
- Three different async patterns in the same codebase
|
|
89
|
-
- Build systems that require arcane incantations
|
|
90
|
-
|
|
91
|
-
...they stumble. Repeatedly. Every session starts from zero.
|
|
92
|
-
|
|
93
|
-
### Panopticon's Unique Solution: Adaptive Learning
|
|
94
|
-
|
|
95
|
-
Panopticon includes two AI self-monitoring skills that **no other orchestration framework provides**:
|
|
96
|
-
|
|
97
|
-
| Skill | What It Does | Business Impact |
|
|
98
|
-
|-------|--------------|-----------------|
|
|
99
|
-
| **Knowledge Capture** | Detects when AI makes mistakes or gets corrected, prompts to document the learning | AI gets smarter about YOUR codebase over time |
|
|
100
|
-
| **Refactor Radar** | Identifies systemic code issues causing repeated AI confusion, creates actionable proposals | Surfaces technical debt that's costing you AI productivity |
|
|
101
|
-
|
|
102
|
-
#### How It Works
|
|
103
|
-
|
|
104
|
-
```
|
|
105
|
-
Session 1: AI queries users.created_at → Error (column is "createdAt")
|
|
106
|
-
→ Knowledge Capture prompts: "Document this convention?"
|
|
107
|
-
→ User: "Yes, create skill"
|
|
108
|
-
→ Creates project-specific skill documenting naming conventions
|
|
109
|
-
|
|
110
|
-
Session 2: AI knows to use camelCase for this project
|
|
111
|
-
No more mistakes on column names
|
|
112
|
-
|
|
113
|
-
Session 5: Refactor Radar detects: "Same entity called 'user', 'account', 'member'
|
|
114
|
-
across layers - this is causing repeated confusion"
|
|
115
|
-
→ Offers to create issue with refactoring proposal
|
|
116
|
-
→ Tech lead reviews and schedules cleanup sprint
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
#### The Compound Effect
|
|
120
|
-
|
|
121
|
-
| Week | Without Panopticon | With Panopticon |
|
|
122
|
-
|------|-------------------|-----------------|
|
|
123
|
-
| 1 | AI makes 20 mistakes/day on conventions | AI makes 20 mistakes, captures 8 learnings |
|
|
124
|
-
| 2 | AI makes 20 mistakes/day (no memory) | AI makes 12 mistakes, captures 5 more |
|
|
125
|
-
| 4 | AI makes 20 mistakes/day (still no memory) | AI makes 3 mistakes, codebase improving |
|
|
126
|
-
| 8 | Developers give up on AI for legacy code | AI is productive, tech debt proposals in backlog |
|
|
127
|
-
|
|
128
|
-
#### Shared Team Knowledge
|
|
129
|
-
|
|
130
|
-
**When one developer learns, everyone benefits.**
|
|
131
|
-
|
|
132
|
-
Captured skills live in your project's `.claude/skills/` directory - they're version-controlled alongside your code. When Sarah documents that "we use camelCase columns" after hitting that error, every developer on the team - and every AI session from that point forward - inherits that knowledge automatically.
|
|
133
|
-
|
|
134
|
-
```
|
|
135
|
-
myproject/
|
|
136
|
-
├── .claude/skills/
|
|
137
|
-
│ └── project-knowledge/ # ← Git-tracked, shared by entire team
|
|
138
|
-
│ └── SKILL.md # "Database uses camelCase, not snake_case"
|
|
139
|
-
├── src/
|
|
140
|
-
└── ...
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
No more repeating the same corrections to AI across 10 different developers. No more tribal knowledge locked in one person's head. The team's collective understanding of your codebase becomes permanent, searchable, and automatically applied.
|
|
144
|
-
|
|
145
|
-
**New hire onboarding?** The AI already knows your conventions from day one.
|
|
146
|
-
|
|
147
|
-
#### For Technical Leaders
|
|
148
|
-
|
|
149
|
-
**What gets measured gets managed.** Panopticon's Refactor Radar surfaces the specific patterns that are costing you AI productivity:
|
|
150
|
-
|
|
151
|
-
- "Here are the 5 naming inconsistencies causing 40% of AI errors"
|
|
152
|
-
- "These 3 missing FK constraints led to 12 incorrect deletions last month"
|
|
153
|
-
- "Mixed async patterns in payments module caused 8 rollbacks"
|
|
154
|
-
|
|
155
|
-
Each proposal includes:
|
|
156
|
-
- **Evidence**: Specific file paths and examples
|
|
157
|
-
- **Impact**: How this affects AI (and new developers)
|
|
158
|
-
- **Migration path**: Incremental fix that won't break production
|
|
159
|
-
|
|
160
|
-
#### For Executives
|
|
161
|
-
|
|
162
|
-
**ROI is simple:**
|
|
163
|
-
|
|
164
|
-
- $200K/year senior developer spends 2 hours/day correcting AI on legacy code
|
|
165
|
-
- That's $50K/year in wasted productivity per developer
|
|
166
|
-
- Team of 10 = **$500K/year** in AI friction
|
|
167
|
-
|
|
168
|
-
Panopticon's learning system:
|
|
169
|
-
- Captures corrections once, applies them forever
|
|
170
|
-
- Identifies root causes (not just symptoms)
|
|
171
|
-
- Creates actionable improvement proposals
|
|
172
|
-
- Works across your entire AI toolchain (Claude, Codex, Cursor, Gemini)
|
|
173
|
-
|
|
174
|
-
**This isn't "AI for greenfield only." This is AI that learns your business.**
|
|
175
|
-
|
|
176
|
-
#### Configurable Per Team and Per Developer
|
|
177
|
-
|
|
178
|
-
Different teams have different ownership boundaries. Individual developers have different preferences. Panopticon respects both:
|
|
179
|
-
|
|
180
|
-
```markdown
|
|
181
|
-
# In ~/.claude/CLAUDE.md (developer's personal config)
|
|
182
|
-
|
|
183
|
-
## AI Suggestion Preferences
|
|
184
|
-
|
|
185
|
-
### refactor-radar
|
|
186
|
-
skip: database-migrations, infrastructure # DBA/Platform team handles these
|
|
187
|
-
welcome: naming, code-organization # Always happy for these
|
|
188
|
-
|
|
189
|
-
### knowledge-capture
|
|
190
|
-
skip: authentication # Security team owns this
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
- **"Skip database migrations"** - Your DBA has a change management process
|
|
194
|
-
- **"Skip infrastructure"** - Platform team owns that
|
|
195
|
-
- **"Welcome naming fixes"** - Low risk, high value, always appreciated
|
|
196
|
-
|
|
197
|
-
The AI adapts to your org structure, not the other way around.
|
|
198
|
-
|
|
199
|
-
---
|
|
200
|
-
|
|
201
|
-
## 🚀 Quick Start
|
|
110
|
+
## Quick Start
|
|
202
111
|
|
|
203
112
|
```bash
|
|
204
113
|
npm install -g panopticon-cli && pan install && pan sync && pan up
|
|
@@ -206,11 +115,9 @@ npm install -g panopticon-cli && pan install && pan sync && pan up
|
|
|
206
115
|
|
|
207
116
|
**That's it!** Dashboard runs at https://pan.localhost (or http://localhost:3010 if you skip HTTPS setup).
|
|
208
117
|
|
|
209
|
-
📖 **[Full documentation →](docs/INDEX.md)**
|
|
210
|
-
|
|
211
118
|
---
|
|
212
119
|
|
|
213
|
-
##
|
|
120
|
+
## Requirements
|
|
214
121
|
|
|
215
122
|
### Required
|
|
216
123
|
- Node.js 18+
|
|
@@ -222,14 +129,12 @@ npm install -g panopticon-cli && pan install && pan sync && pan up
|
|
|
222
129
|
|
|
223
130
|
### Optional
|
|
224
131
|
- **mkcert** - For HTTPS certificates (recommended)
|
|
225
|
-
- **Linear API key** - For issue tracking
|
|
132
|
+
- **Linear API key** - For Linear issue tracking
|
|
226
133
|
- **Beads CLI** - Auto-installed by `pan install`
|
|
227
134
|
|
|
228
|
-
📖 **[Platform support and detailed requirements →](docs/USAGE.md#requirements)**
|
|
229
|
-
|
|
230
135
|
---
|
|
231
136
|
|
|
232
|
-
##
|
|
137
|
+
## Configuration
|
|
233
138
|
|
|
234
139
|
```bash
|
|
235
140
|
# Create config file
|
|
@@ -246,49 +151,27 @@ Register your projects:
|
|
|
246
151
|
pan project add /path/to/your/project --name myproject
|
|
247
152
|
```
|
|
248
153
|
|
|
249
|
-
📖 **[Complete configuration guide →](docs/CONFIGURATION.md)**
|
|
250
|
-
📖 **[Work types and model routing →](docs/WORK-TYPES.md)**
|
|
251
|
-
📖 **[Detailed usage examples →](docs/USAGE.md)**
|
|
252
|
-
|
|
253
154
|
---
|
|
254
155
|
|
|
255
|
-
##
|
|
156
|
+
## Key Concepts
|
|
256
157
|
|
|
257
|
-
|
|
258
|
-
The default landing view. A two-panel layout with a resizable sidebar showing your project tree (grouped by project, filtered to active features) and a main area displaying agent activity, planning artifacts (PRD, STATE.md, transcripts, discussions), and status reviews.
|
|
158
|
+
**Mission Control** — The default view. Project tree on the left, agent activity on the right. Click a feature to see its full pipeline: planning, work, review, test results. Badge bar gives quick access to PRDs, state files, discussions, and transcripts.
|
|
259
159
|
|
|
260
|
-
|
|
261
|
-
- **Activity View**: Chronological agent sessions with tail-anchored scrolling — click a feature and see what the agent is doing right now
|
|
262
|
-
- **Badge Bar**: Quick access to PRD, STATE.md, discussions, transcripts, status reviews, and file uploads
|
|
263
|
-
- **Status Reviews**: On-demand AI-generated progress reports comparing code changes against the PRD
|
|
160
|
+
**Cloister** — The lifecycle manager. Routes tasks to models based on capabilities, detects stuck agents, triggers specialist handoffs, and tracks costs.
|
|
264
161
|
|
|
265
|
-
|
|
266
|
-
A mode for teams adopting AI incrementally. Register existing projects as "shadow" workspaces to monitor ongoing development without AI agents making changes.
|
|
162
|
+
**Workspaces** — Git worktree-based feature branches with optional Docker isolation. Each issue gets its own isolated environment. Supports both local and remote (exe.dev) execution.
|
|
267
163
|
|
|
268
|
-
|
|
269
|
-
- Upload meeting transcripts and notes via the Badge Bar
|
|
270
|
-
- Sync issue tracker discussions automatically
|
|
271
|
-
- Generate inference documents (INFERENCE.md) analyzing how AI would approach the work
|
|
272
|
-
- Transition from monitoring to AI-driven development when ready
|
|
164
|
+
**Specialists** — Dedicated agents for code review, testing, and merging. Triggered automatically by Cloister when an agent signals completion. The pipeline is fully automated — code review to merge with zero human intervention (except the final merge click).
|
|
273
165
|
|
|
274
|
-
|
|
275
|
-
Spawn and manage AI agents in tmux sessions, monitored by the Cloister lifecycle manager.
|
|
166
|
+
**Convoys** — Run parallel agents on related issues. Useful for security audits, performance reviews, or breaking an epic into concurrent work streams. Results are auto-synthesized.
|
|
276
167
|
|
|
277
|
-
|
|
278
|
-
Git worktree-based feature branches with optional Docker isolation. Supports both local and remote (exe.dev) execution.
|
|
168
|
+
**Skills** — Universal SKILL.md format works across Claude Code, Codex, Cursor, and Gemini. 67+ skills ship out of the box covering development workflows, code review, incident response, and more.
|
|
279
169
|
|
|
280
|
-
|
|
281
|
-
Dedicated agents for code review, testing, and merging. Automatically triggered by the Cloister manager.
|
|
282
|
-
|
|
283
|
-
### Skills
|
|
284
|
-
Universal SKILL.md format works across Claude Code, Codex, Cursor, and Gemini. Distributed via `pan sync`.
|
|
285
|
-
|
|
286
|
-
📖 **[Architecture overview →](AGENTS.md)**
|
|
287
|
-
📖 **[Specialist workflow →](docs/SPECIALIST_WORKFLOW.md)**
|
|
170
|
+
**Shadow Engineering** — Monitor existing workflows before transitioning to AI-driven development. Upload transcripts, sync discussions, generate inference documents.
|
|
288
171
|
|
|
289
172
|
---
|
|
290
173
|
|
|
291
|
-
##
|
|
174
|
+
## Common Commands
|
|
292
175
|
|
|
293
176
|
```bash
|
|
294
177
|
# Start dashboard
|
|
@@ -307,11 +190,21 @@ pan logs agent-pan-123
|
|
|
307
190
|
pan down
|
|
308
191
|
```
|
|
309
192
|
|
|
310
|
-
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Maturity
|
|
196
|
+
|
|
197
|
+
Panopticon is actively used in production to develop itself and multiple other projects.
|
|
198
|
+
|
|
199
|
+
- **62 PRDs** written (16 active, 46 completed)
|
|
200
|
+
- **67+ skills** shipped and synced across tools
|
|
201
|
+
- **5 tracker integrations** (GitHub, Linear, GitLab, Jira, Rally)
|
|
202
|
+
- **6 AI providers** with capability-based model routing
|
|
203
|
+
- **v0.4.33** — hundreds of issues completed through the full pipeline
|
|
311
204
|
|
|
312
205
|
---
|
|
313
206
|
|
|
314
|
-
##
|
|
207
|
+
## Documentation
|
|
315
208
|
|
|
316
209
|
| Document | Description |
|
|
317
210
|
|----------|-------------|
|
|
@@ -319,32 +212,25 @@ pan down
|
|
|
319
212
|
| [docs/USAGE.md](docs/USAGE.md) | Detailed usage guide, examples, troubleshooting |
|
|
320
213
|
| [docs/CONFIGURATION.md](docs/CONFIGURATION.md) | Model routing, API setup, presets |
|
|
321
214
|
| [AGENTS.md](AGENTS.md) | Agent architecture |
|
|
322
|
-
| [docs/
|
|
215
|
+
| [docs/SPECIALIST_WORKFLOW.md](docs/SPECIALIST_WORKFLOW.md) | Review, test, merge pipeline |
|
|
216
|
+
| [docs/LEGACY-CODEBASE.md](docs/LEGACY-CODEBASE.md) | AI adaptive learning for legacy codebases |
|
|
323
217
|
| [CONTRIBUTING.md](CONTRIBUTING.md) | Contribution guidelines |
|
|
324
218
|
| [CLAUDE.md](CLAUDE.md) | Agent development guidance |
|
|
325
|
-
| [docs/MISSION-CONTROL.md](docs/MISSION-CONTROL.md) | Mission Control and Shadow Engineering guide |
|
|
326
219
|
|
|
327
220
|
---
|
|
328
221
|
|
|
329
|
-
##
|
|
222
|
+
## Contributing
|
|
330
223
|
|
|
331
224
|
Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
332
225
|
|
|
333
226
|
---
|
|
334
227
|
|
|
335
|
-
##
|
|
336
|
-
|
|
337
|
-
[](https://star-history.com/#eltmon/panopticon-cli&Date)
|
|
338
|
-
|
|
339
|
-
---
|
|
340
|
-
|
|
341
|
-
## ⚖️ License
|
|
228
|
+
## License
|
|
342
229
|
|
|
343
230
|
MIT License - see [LICENSE](LICENSE) for details.
|
|
344
231
|
|
|
345
232
|
---
|
|
346
233
|
|
|
347
234
|
<div align="center">
|
|
348
|
-
<p><strong>Made with ❤️ by the Panopticon team</strong></p>
|
|
349
235
|
<p><a href="https://github.com/eltmon/panopticon-cli">GitHub</a> · <a href="https://www.npmjs.com/package/panopticon-cli">npm</a> · <a href="docs/INDEX.md">Documentation</a></p>
|
|
350
236
|
</div>
|
|
@@ -18,11 +18,12 @@ import {
|
|
|
18
18
|
saveSessionId,
|
|
19
19
|
spawnAgent,
|
|
20
20
|
stopAgent
|
|
21
|
-
} from "./chunk-
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
21
|
+
} from "./chunk-VHKSS7QX.js";
|
|
22
|
+
import "./chunk-FTCPTHIJ.js";
|
|
23
|
+
import "./chunk-76F6DSVS.js";
|
|
24
|
+
import "./chunk-HJSM6E6U.js";
|
|
25
25
|
import "./chunk-FQ66DECN.js";
|
|
26
|
+
import "./chunk-2V4NF7J2.js";
|
|
26
27
|
import "./chunk-CFCUOV3Q.js";
|
|
27
28
|
import "./chunk-ZTFNYOC7.js";
|
|
28
29
|
import "./chunk-ZHC57RCV.js";
|
|
@@ -47,4 +48,4 @@ export {
|
|
|
47
48
|
spawnAgent,
|
|
48
49
|
stopAgent
|
|
49
50
|
};
|
|
50
|
-
//# sourceMappingURL=agents-
|
|
51
|
+
//# sourceMappingURL=agents-5OPQKM5K.js.map
|
|
@@ -14,6 +14,7 @@ __export(projects_exports, {
|
|
|
14
14
|
PROJECTS_CONFIG_FILE: () => PROJECTS_CONFIG_FILE,
|
|
15
15
|
createDefaultProjectsConfig: () => createDefaultProjectsConfig,
|
|
16
16
|
extractTeamPrefix: () => extractTeamPrefix,
|
|
17
|
+
findProjectByPath: () => findProjectByPath,
|
|
17
18
|
findProjectByTeam: () => findProjectByTeam,
|
|
18
19
|
findProjectsByRallyProject: () => findProjectsByRallyProject,
|
|
19
20
|
getProject: () => getProject,
|
|
@@ -88,6 +89,17 @@ function findProjectByTeam(teamPrefix) {
|
|
|
88
89
|
}
|
|
89
90
|
return null;
|
|
90
91
|
}
|
|
92
|
+
function findProjectByPath(workspacePath) {
|
|
93
|
+
const config = loadProjectsConfig();
|
|
94
|
+
const normalizedTarget = resolve(workspacePath);
|
|
95
|
+
for (const [, projectConfig] of Object.entries(config.projects)) {
|
|
96
|
+
const normalizedProject = resolve(projectConfig.path);
|
|
97
|
+
if (normalizedTarget === normalizedProject || normalizedTarget.startsWith(normalizedProject + "/")) {
|
|
98
|
+
return projectConfig;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
91
103
|
function resolveProjectPath(project, labels = []) {
|
|
92
104
|
if (!project.issue_routing || project.issue_routing.length === 0) {
|
|
93
105
|
return project.path;
|
|
@@ -244,6 +256,7 @@ export {
|
|
|
244
256
|
unregisterProject,
|
|
245
257
|
extractTeamPrefix,
|
|
246
258
|
findProjectByTeam,
|
|
259
|
+
findProjectByPath,
|
|
247
260
|
resolveProjectPath,
|
|
248
261
|
resolveProjectFromIssue,
|
|
249
262
|
getProject,
|
|
@@ -257,4 +270,4 @@ export {
|
|
|
257
270
|
projects_exports,
|
|
258
271
|
init_projects
|
|
259
272
|
};
|
|
260
|
-
//# sourceMappingURL=chunk-
|
|
273
|
+
//# sourceMappingURL=chunk-2V4NF7J2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/projects.ts"],"sourcesContent":["/**\n * Project Registry - Multi-project support for Panopticon\n *\n * Maps Linear team prefixes and labels to project paths for workspace creation.\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\nimport { PANOPTICON_HOME } from './paths.js';\n\nexport const PROJECTS_CONFIG_FILE = join(PANOPTICON_HOME, 'projects.yaml');\n\n/**\n * Issue routing rule - routes issues with certain labels to specific paths\n */\nexport interface IssueRoutingRule {\n labels?: string[];\n default?: boolean;\n path: string;\n}\n\n/**\n * Workspace configuration (imported from workspace-config.ts for full details)\n */\nexport interface WorkspaceConfig {\n type?: 'polyrepo' | 'monorepo';\n workspaces_dir?: string;\n repos?: Array<{ name: string; path: string; branch_prefix?: string }>;\n dns?: { domain: string; entries: string[]; sync_method?: 'wsl2hosts' | 'hosts_file' | 'dnsmasq' };\n ports?: Record<string, { range: [number, number] }>;\n docker?: { traefik?: string; compose_template?: string };\n database?: { seed_file?: string; container_name?: string; [key: string]: any };\n agent?: { template_dir: string; templates?: Array<{ source: string; target: string }>; copy_dirs?: string[]; symlinks?: string[] };\n env?: { template?: string; secrets_file?: string };\n services?: Array<{ name: string; path: string; start_command: string; docker_command?: string; health_url?: string; port?: number }>;\n}\n\n/**\n * Test configuration\n */\nexport interface TestConfig {\n type: string;\n path: string;\n command: string;\n container?: boolean;\n container_name?: string;\n env?: Record<string, string>;\n}\n\n/**\n * Specialist configuration for per-project specialists\n */\nexport interface SpecialistConfig {\n /** Number of recent runs to include in context digest (default: 5) */\n context_runs?: number;\n /** Model to use for generating context digests (null = same as specialist) */\n digest_model?: string | null;\n /** Log retention policy */\n retention?: {\n /** Maximum days to keep logs */\n max_days: number;\n /** Maximum number of runs to keep (whichever is more permissive) */\n max_runs: number;\n };\n /** Per-specialist prompt overrides */\n prompts?: {\n 'review-agent'?: string;\n 'test-agent'?: string;\n 'merge-agent'?: string;\n };\n}\n\n/**\n * Project configuration\n */\nexport interface ProjectConfig {\n name: string;\n path: string;\n linear_team?: string;\n github_repo?: string; // e.g. \"owner/repo\"\n gitlab_repo?: string; // e.g. \"group/repo\"\n issue_routing?: IssueRoutingRule[];\n /** Workspace configuration */\n workspace?: WorkspaceConfig;\n /** Test configuration by name */\n tests?: Record<string, TestConfig>;\n /** Custom command to create workspaces (e.g., infra/new-feature for MYN) */\n workspace_command?: string;\n /** Custom command to remove workspaces */\n workspace_remove_command?: string;\n /** Rally project OID (e.g., \"/project/822404704163\") for per-project Rally scoping */\n rally_project?: string;\n /** Specialist agent configuration */\n specialists?: SpecialistConfig;\n}\n\n/**\n * Full projects configuration file\n */\nexport interface ProjectsConfig {\n projects: Record<string, ProjectConfig>;\n}\n\n/**\n * Resolved project info for workspace creation\n */\nexport interface ResolvedProject {\n projectKey: string;\n projectName: string;\n projectPath: string;\n linearTeam?: string;\n}\n\n/**\n * Load projects configuration from ~/.panopticon/projects.yaml\n */\nexport function loadProjectsConfig(): ProjectsConfig {\n if (!existsSync(PROJECTS_CONFIG_FILE)) {\n return { projects: {} };\n }\n\n try {\n const content = readFileSync(PROJECTS_CONFIG_FILE, 'utf-8');\n const config = parseYaml(content) as ProjectsConfig;\n return config || { projects: {} };\n } catch (error: any) {\n console.error(`Failed to parse projects.yaml: ${error.message}`);\n return { projects: {} };\n }\n}\n\n/**\n * Save projects configuration\n */\nexport function saveProjectsConfig(config: ProjectsConfig): void {\n const dir = PANOPTICON_HOME;\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n const yaml = stringifyYaml(config, { indent: 2 });\n writeFileSync(PROJECTS_CONFIG_FILE, yaml, 'utf-8');\n}\n\n/**\n * Get a list of all registered projects\n */\nexport function listProjects(): Array<{ key: string; config: ProjectConfig }> {\n const config = loadProjectsConfig();\n return Object.entries(config.projects).map(([key, projectConfig]) => ({\n key,\n config: projectConfig,\n }));\n}\n\n/**\n * Add or update a project in the registry\n */\nexport function registerProject(key: string, projectConfig: ProjectConfig): void {\n const config = loadProjectsConfig();\n config.projects[key] = projectConfig;\n saveProjectsConfig(config);\n}\n\n/**\n * Remove a project from the registry\n */\nexport function unregisterProject(key: string): boolean {\n const config = loadProjectsConfig();\n if (config.projects[key]) {\n delete config.projects[key];\n saveProjectsConfig(config);\n return true;\n }\n return false;\n}\n\n/**\n * Extract Linear team prefix from an issue ID\n * E.g., \"MIN-123\" -> \"MIN\", \"PAN-456\" -> \"PAN\"\n */\nexport function extractTeamPrefix(issueId: string): string | null {\n const match = issueId.match(/^([A-Z]+)-\\d+$/i);\n return match ? match[1].toUpperCase() : null;\n}\n\n/**\n * Find project by Linear team prefix\n */\nexport function findProjectByTeam(teamPrefix: string): ProjectConfig | null {\n const config = loadProjectsConfig();\n\n for (const [, projectConfig] of Object.entries(config.projects)) {\n if (projectConfig.linear_team?.toUpperCase() === teamPrefix.toUpperCase()) {\n return projectConfig;\n }\n }\n\n return null;\n}\n\n/**\n * Find project by workspace path.\n * Matches any project whose root path is an ancestor of the given path.\n * Used to resolve the tracker (GitHub/GitLab) from a workspace directory.\n */\nexport function findProjectByPath(workspacePath: string): ProjectConfig | null {\n const config = loadProjectsConfig();\n const normalizedTarget = resolve(workspacePath);\n\n for (const [, projectConfig] of Object.entries(config.projects)) {\n const normalizedProject = resolve(projectConfig.path);\n if (normalizedTarget === normalizedProject || normalizedTarget.startsWith(normalizedProject + '/')) {\n return projectConfig;\n }\n }\n\n return null;\n}\n\n/**\n * Resolve the correct project path for an issue based on labels\n *\n * @param project - The project config\n * @param labels - Array of label names from the Linear issue\n * @returns The resolved path (may differ from project.path based on routing rules)\n */\nexport function resolveProjectPath(project: ProjectConfig, labels: string[] = []): string {\n if (!project.issue_routing || project.issue_routing.length === 0) {\n return project.path;\n }\n\n // Normalize labels to lowercase for comparison\n const normalizedLabels = labels.map(l => l.toLowerCase());\n\n // First, check label-based routing rules\n for (const rule of project.issue_routing) {\n if (rule.labels && rule.labels.length > 0) {\n const ruleLabels = rule.labels.map(l => l.toLowerCase());\n const hasMatch = ruleLabels.some(label => normalizedLabels.includes(label));\n if (hasMatch) {\n return rule.path;\n }\n }\n }\n\n // Then, find default rule\n for (const rule of project.issue_routing) {\n if (rule.default) {\n return rule.path;\n }\n }\n\n // Fall back to project path\n return project.path;\n}\n\n/**\n * Resolve project from an issue ID (and optional labels)\n *\n * @param issueId - Linear issue ID (e.g., \"MIN-123\")\n * @param labels - Optional array of label names\n * @returns Resolved project info or null if not found\n */\nexport function resolveProjectFromIssue(\n issueId: string,\n labels: string[] = []\n): ResolvedProject | null {\n const teamPrefix = extractTeamPrefix(issueId);\n if (!teamPrefix) {\n return null;\n }\n\n const config = loadProjectsConfig();\n\n // Find project by team prefix\n for (const [key, projectConfig] of Object.entries(config.projects)) {\n if (projectConfig.linear_team?.toUpperCase() === teamPrefix) {\n const resolvedPath = resolveProjectPath(projectConfig, labels);\n return {\n projectKey: key,\n projectName: projectConfig.name,\n projectPath: resolvedPath,\n linearTeam: projectConfig.linear_team,\n };\n }\n }\n\n return null;\n}\n\n/**\n * Get a project by key\n */\nexport function getProject(key: string): ProjectConfig | null {\n const config = loadProjectsConfig();\n return config.projects[key] || null;\n}\n\n/**\n * Check if projects.yaml exists and has any projects\n */\nexport function hasProjects(): boolean {\n const config = loadProjectsConfig();\n return Object.keys(config.projects).length > 0;\n}\n\n/**\n * Create a default projects.yaml with example structure\n */\nexport function createDefaultProjectsConfig(): ProjectsConfig {\n const defaultConfig: ProjectsConfig = {\n projects: {\n // Example project - commented out in actual file\n },\n };\n\n return defaultConfig;\n}\n\n/**\n * Initialize projects.yaml with example configuration\n */\nexport function initializeProjectsConfig(): void {\n if (existsSync(PROJECTS_CONFIG_FILE)) {\n console.log(`Projects config already exists at ${PROJECTS_CONFIG_FILE}`);\n return;\n }\n\n const exampleYaml = `# Panopticon Project Registry\n# Maps Linear teams to project paths for workspace creation\n\nprojects:\n # Example: Mind Your Now project\n # myn:\n # name: \"Mind Your Now\"\n # path: /home/user/projects/myn\n # linear_team: MIN\n # issue_routing:\n # # Route docs/marketing issues to docs repo\n # - labels: [docs, marketing, seo, landing-pages]\n # path: /home/user/projects/myn/docs\n # # Default: main repo\n # - default: true\n # path: /home/user/projects/myn\n # specialists:\n # context_runs: 5\n # digest_model: null # Use same model as specialist\n # retention:\n # max_days: 30\n # max_runs: 50\n # prompts:\n # review-agent: |\n # Pay special attention to:\n # - Database migration safety\n # - API backward compatibility\n\n # Example: Panopticon itself\n # panopticon:\n # name: \"Panopticon\"\n # path: /home/user/projects/panopticon\n # linear_team: PAN\n`;\n\n const dir = PANOPTICON_HOME;\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n writeFileSync(PROJECTS_CONFIG_FILE, exampleYaml, 'utf-8');\n console.log(`Created example projects config at ${PROJECTS_CONFIG_FILE}`);\n}\n\n/**\n * Default specialist configuration values\n */\nconst DEFAULT_SPECIALIST_CONFIG: Required<SpecialistConfig> = {\n context_runs: 5,\n digest_model: null,\n retention: {\n max_days: 30,\n max_runs: 50,\n },\n prompts: {},\n};\n\n/**\n * Get specialist configuration for a project with defaults\n *\n * @param projectKey - Project key\n * @returns Specialist config with defaults applied\n */\nexport function getSpecialistConfig(projectKey: string): Required<SpecialistConfig> {\n const project = getProject(projectKey);\n\n if (!project || !project.specialists) {\n return DEFAULT_SPECIALIST_CONFIG;\n }\n\n return {\n context_runs: project.specialists.context_runs ?? DEFAULT_SPECIALIST_CONFIG.context_runs,\n digest_model: project.specialists.digest_model ?? DEFAULT_SPECIALIST_CONFIG.digest_model,\n retention: {\n max_days: project.specialists.retention?.max_days ?? DEFAULT_SPECIALIST_CONFIG.retention.max_days,\n max_runs: project.specialists.retention?.max_runs ?? DEFAULT_SPECIALIST_CONFIG.retention.max_runs,\n },\n prompts: project.specialists.prompts ?? DEFAULT_SPECIALIST_CONFIG.prompts,\n };\n}\n\n/**\n * Get retention policy for a project's specialists\n *\n * @param projectKey - Project key\n * @returns Retention policy\n */\nexport function getSpecialistRetention(projectKey: string): { max_days: number; max_runs: number } {\n const config = getSpecialistConfig(projectKey);\n return config.retention;\n}\n\n/**\n * Find all projects that have a rally_project configured.\n * Returns array of { key, config } for projects with Rally project OIDs.\n */\nexport function findProjectsByRallyProject(): Array<{ key: string; config: ProjectConfig }> {\n const config = loadProjectsConfig();\n return Object.entries(config.projects)\n .filter(([, projectConfig]) => !!projectConfig.rally_project)\n .map(([key, projectConfig]) => ({ key, config: projectConfig }));\n}\n\n/**\n * Get custom prompt override for a specialist (if configured)\n *\n * @param projectKey - Project key\n * @param specialistType - Specialist type\n * @returns Custom prompt or null if not configured\n */\nexport function getSpecialistPromptOverride(\n projectKey: string,\n specialistType: 'review-agent' | 'test-agent' | 'merge-agent'\n): string | null {\n const config = getSpecialistConfig(projectKey);\n return config.prompts[specialistType] || null;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
init_github,
|
|
14
14
|
init_gitlab,
|
|
15
15
|
init_linear
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-76F6DSVS.js";
|
|
17
17
|
import {
|
|
18
18
|
getDevrootPath,
|
|
19
19
|
init_config
|
|
@@ -674,4 +674,4 @@ export {
|
|
|
674
674
|
LinkManager,
|
|
675
675
|
getLinkManager
|
|
676
676
|
};
|
|
677
|
-
//# sourceMappingURL=chunk-
|
|
677
|
+
//# sourceMappingURL=chunk-4YSYJ4HM.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
init_config_yaml,
|
|
3
3
|
loadConfig
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HJSM6E6U.js";
|
|
5
5
|
import {
|
|
6
6
|
IssueNotFoundError,
|
|
7
7
|
NotImplementedError,
|
|
@@ -370,7 +370,43 @@ var init_github = __esm({
|
|
|
370
370
|
};
|
|
371
371
|
}
|
|
372
372
|
async transitionIssue(id, state) {
|
|
373
|
-
|
|
373
|
+
const issueNumber = parseInt(id.replace(/^#/, ""), 10);
|
|
374
|
+
if (state === "in_progress") {
|
|
375
|
+
await this.ensureLabelExists("in-progress", "In progress", "0075ca");
|
|
376
|
+
await this.octokit.issues.addLabels({
|
|
377
|
+
owner: this.owner,
|
|
378
|
+
repo: this.repo,
|
|
379
|
+
issue_number: issueNumber,
|
|
380
|
+
labels: ["in-progress"]
|
|
381
|
+
});
|
|
382
|
+
} else {
|
|
383
|
+
const issue = await this.getIssue(id);
|
|
384
|
+
if (issue.labels?.includes("in-progress")) {
|
|
385
|
+
await this.octokit.issues.removeLabel({
|
|
386
|
+
owner: this.owner,
|
|
387
|
+
repo: this.repo,
|
|
388
|
+
issue_number: issueNumber,
|
|
389
|
+
name: "in-progress"
|
|
390
|
+
}).catch(() => {
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
await this.updateIssue(id, { state });
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/** Ensure a label exists in the repo, creating it if needed. */
|
|
397
|
+
async ensureLabelExists(name, description, color) {
|
|
398
|
+
try {
|
|
399
|
+
await this.octokit.issues.getLabel({ owner: this.owner, repo: this.repo, name });
|
|
400
|
+
} catch {
|
|
401
|
+
await this.octokit.issues.createLabel({
|
|
402
|
+
owner: this.owner,
|
|
403
|
+
repo: this.repo,
|
|
404
|
+
name,
|
|
405
|
+
description,
|
|
406
|
+
color
|
|
407
|
+
}).catch(() => {
|
|
408
|
+
});
|
|
409
|
+
}
|
|
374
410
|
}
|
|
375
411
|
async linkPR(issueId, prUrl) {
|
|
376
412
|
await this.addComment(
|
|
@@ -379,15 +415,16 @@ var init_github = __esm({
|
|
|
379
415
|
);
|
|
380
416
|
}
|
|
381
417
|
normalizeIssue(ghIssue) {
|
|
418
|
+
const labels = ghIssue.labels.map(
|
|
419
|
+
(l) => typeof l === "string" ? l : l.name
|
|
420
|
+
);
|
|
382
421
|
return {
|
|
383
422
|
id: String(ghIssue.id),
|
|
384
423
|
ref: `#${ghIssue.number}`,
|
|
385
424
|
title: ghIssue.title,
|
|
386
425
|
description: ghIssue.body ?? "",
|
|
387
|
-
state: this.mapStateFromGitHub(ghIssue.state),
|
|
388
|
-
labels
|
|
389
|
-
(l) => typeof l === "string" ? l : l.name
|
|
390
|
-
),
|
|
426
|
+
state: this.mapStateFromGitHub(ghIssue.state, labels),
|
|
427
|
+
labels,
|
|
391
428
|
assignee: ghIssue.assignee?.login,
|
|
392
429
|
url: ghIssue.html_url,
|
|
393
430
|
tracker: "github",
|
|
@@ -399,8 +436,10 @@ var init_github = __esm({
|
|
|
399
436
|
updatedAt: ghIssue.updated_at
|
|
400
437
|
};
|
|
401
438
|
}
|
|
402
|
-
mapStateFromGitHub(ghState) {
|
|
403
|
-
|
|
439
|
+
mapStateFromGitHub(ghState, labels = []) {
|
|
440
|
+
if (ghState === "closed") return "closed";
|
|
441
|
+
if (labels.includes("in-progress")) return "in_progress";
|
|
442
|
+
return "open";
|
|
404
443
|
}
|
|
405
444
|
mapStateToGitHub(state) {
|
|
406
445
|
if (!state) return "open";
|
|
@@ -471,7 +510,7 @@ var init_gitlab = __esm({
|
|
|
471
510
|
// src/lib/tracker/factory.ts
|
|
472
511
|
function getTrackerKeyFromConfig(trackerType) {
|
|
473
512
|
try {
|
|
474
|
-
const yamlConfig = loadConfig();
|
|
513
|
+
const { config: yamlConfig } = loadConfig();
|
|
475
514
|
return yamlConfig.trackerKeys[trackerType];
|
|
476
515
|
} catch {
|
|
477
516
|
return void 0;
|
|
@@ -597,4 +636,4 @@ export {
|
|
|
597
636
|
getAllTrackers,
|
|
598
637
|
init_factory
|
|
599
638
|
};
|
|
600
|
-
//# sourceMappingURL=chunk-
|
|
639
|
+
//# sourceMappingURL=chunk-76F6DSVS.js.map
|