panopticon-cli 0.4.32 → 0.5.0
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-BDFHF4T3.js → agents-E43Y3HNU.js} +10 -7
- package/dist/chunk-7SN4L4PH.js +150 -0
- package/dist/chunk-7SN4L4PH.js.map +1 -0
- package/dist/{chunk-2NIAOCIC.js → chunk-AAFQANKW.js} +358 -97
- package/dist/chunk-AAFQANKW.js.map +1 -0
- package/dist/chunk-AQXETQHW.js +113 -0
- package/dist/chunk-AQXETQHW.js.map +1 -0
- package/dist/chunk-B3PF6JPQ.js +212 -0
- package/dist/chunk-B3PF6JPQ.js.map +1 -0
- package/dist/chunk-CFCUOV3Q.js +669 -0
- package/dist/chunk-CFCUOV3Q.js.map +1 -0
- package/dist/chunk-CWELWPWQ.js +32 -0
- package/dist/chunk-CWELWPWQ.js.map +1 -0
- package/dist/chunk-DI7ABPNQ.js +352 -0
- package/dist/chunk-DI7ABPNQ.js.map +1 -0
- package/dist/{chunk-VU4FLXV5.js → chunk-FQ66DECN.js} +31 -4
- package/dist/chunk-FQ66DECN.js.map +1 -0
- package/dist/{chunk-VIWUCJ4V.js → chunk-FTCPTHIJ.js} +57 -432
- package/dist/chunk-FTCPTHIJ.js.map +1 -0
- package/dist/{review-status-GWQYY77L.js → chunk-GFP3PIPB.js} +14 -7
- package/dist/chunk-GFP3PIPB.js.map +1 -0
- package/dist/chunk-GR6ZZMCX.js +816 -0
- package/dist/chunk-GR6ZZMCX.js.map +1 -0
- package/dist/chunk-HJSM6E6U.js +1038 -0
- package/dist/chunk-HJSM6E6U.js.map +1 -0
- package/dist/{chunk-XP2DXWYP.js → chunk-HZT2AOPN.js} +164 -39
- package/dist/chunk-HZT2AOPN.js.map +1 -0
- package/dist/chunk-JQBV3Q2W.js +29 -0
- package/dist/chunk-JQBV3Q2W.js.map +1 -0
- package/dist/{chunk-BWGFN44T.js → chunk-JT4O4YVM.js} +28 -16
- package/dist/chunk-JT4O4YVM.js.map +1 -0
- package/dist/chunk-NTO3EDB3.js +600 -0
- package/dist/chunk-NTO3EDB3.js.map +1 -0
- package/dist/{chunk-JY7R7V4G.js → chunk-OMNXYPXC.js} +2 -2
- package/dist/chunk-OMNXYPXC.js.map +1 -0
- package/dist/chunk-PELXV435.js +215 -0
- package/dist/chunk-PELXV435.js.map +1 -0
- package/dist/chunk-PPRFKTVC.js +154 -0
- package/dist/chunk-PPRFKTVC.js.map +1 -0
- package/dist/chunk-WQG2TYCB.js +677 -0
- package/dist/chunk-WQG2TYCB.js.map +1 -0
- package/dist/{chunk-HCTJFIJJ.js → chunk-YLPSQAM2.js} +2 -2
- package/dist/{chunk-HCTJFIJJ.js.map → chunk-YLPSQAM2.js.map} +1 -1
- package/dist/{chunk-6HXKTOD7.js → chunk-ZTFNYOC7.js} +53 -38
- package/dist/chunk-ZTFNYOC7.js.map +1 -0
- package/dist/cli/index.js +5103 -3165
- package/dist/cli/index.js.map +1 -1
- package/dist/{config-BOAMSKTF.js → config-4CJNUE3O.js} +7 -3
- package/dist/dashboard/prompts/merge-agent.md +217 -0
- package/dist/dashboard/prompts/review-agent.md +409 -0
- package/dist/dashboard/prompts/sync-main.md +84 -0
- package/dist/dashboard/prompts/test-agent.md +283 -0
- package/dist/dashboard/prompts/work-agent.md +249 -0
- package/dist/dashboard/public/assets/index-BxpjweAL.css +32 -0
- package/dist/dashboard/public/assets/index-DQHkwvvJ.js +743 -0
- package/dist/dashboard/public/index.html +2 -2
- package/dist/dashboard/server.js +17619 -4044
- package/dist/{dns-L3L2BB27.js → dns-7BDJSD3E.js} +4 -2
- package/dist/{feedback-writer-AAKF5BTK.js → feedback-writer-LVZ5TFYZ.js} +8 -4
- package/dist/feedback-writer-LVZ5TFYZ.js.map +1 -0
- package/dist/hume-WMAUBBV2.js +13 -0
- package/dist/index.d.ts +162 -40
- package/dist/index.js +67 -23
- package/dist/index.js.map +1 -1
- package/dist/{projects-VXRUCMLM.js → projects-JEIVIYC6.js} +3 -3
- package/dist/rally-RKFSWC7E.js +10 -0
- package/dist/{remote-agents-Z3R2A5BN.js → remote-agents-TFSMW7GN.js} +2 -2
- package/dist/{remote-workspace-2G6V2KNP.js → remote-workspace-AHVHQEES.js} +8 -8
- package/dist/review-status-EPFG4XM7.js +19 -0
- package/dist/shadow-state-5MDP6YXH.js +30 -0
- package/dist/shadow-state-5MDP6YXH.js.map +1 -0
- package/dist/{specialist-context-N32QBNNQ.js → specialist-context-ZC6A4M3I.js} +8 -7
- package/dist/{specialist-context-N32QBNNQ.js.map → specialist-context-ZC6A4M3I.js.map} +1 -1
- package/dist/{specialist-logs-GF3YV4KL.js → specialist-logs-KLGJCEUL.js} +7 -6
- package/dist/specialist-logs-KLGJCEUL.js.map +1 -0
- package/dist/{specialists-JBIW6MP4.js → specialists-O4HWDJL5.js} +7 -6
- package/dist/specialists-O4HWDJL5.js.map +1 -0
- package/dist/tldr-daemon-T3THOUGT.js +21 -0
- package/dist/tldr-daemon-T3THOUGT.js.map +1 -0
- package/dist/traefik-QN7R5I6V.js +19 -0
- package/dist/traefik-QN7R5I6V.js.map +1 -0
- package/dist/tunnel-W2GZBLEV.js +13 -0
- package/dist/tunnel-W2GZBLEV.js.map +1 -0
- package/dist/workspace-manager-IE4JL2JP.js +22 -0
- package/dist/workspace-manager-IE4JL2JP.js.map +1 -0
- package/package.json +2 -2
- package/scripts/heartbeat-hook +37 -10
- package/scripts/patches/llm-tldr-tsx-support.py +109 -0
- package/scripts/pre-tool-hook +26 -15
- package/scripts/record-cost-event.js +177 -43
- package/scripts/record-cost-event.ts +87 -3
- package/scripts/statusline.sh +169 -0
- package/scripts/stop-hook +21 -11
- package/scripts/tldr-post-edit +72 -0
- package/scripts/tldr-read-enforcer +275 -0
- package/scripts/work-agent-stop-hook +137 -0
- package/skills/check-merged/SKILL.md +143 -0
- package/skills/crash-investigation/SKILL.md +301 -0
- package/skills/github-cli/SKILL.md +185 -0
- package/skills/myn-standards/SKILL.md +351 -0
- package/skills/pan-reopen/SKILL.md +65 -0
- package/skills/pan-sync-main/SKILL.md +87 -0
- package/skills/pan-tldr/SKILL.md +149 -0
- package/skills/react-best-practices/SKILL.md +125 -0
- package/skills/spec-readiness/REPORT-TEMPLATE.md +158 -0
- package/skills/spec-readiness/SCORING-REFERENCE.md +369 -0
- package/skills/spec-readiness/SKILL.md +400 -0
- package/skills/spec-readiness-setup/SKILL.md +361 -0
- package/skills/workspace-status/SKILL.md +56 -0
- package/skills/write-spec/SKILL.md +138 -0
- package/templates/traefik/dynamic/panopticon.yml.template +0 -5
- package/templates/traefik/traefik.yml +0 -8
- package/dist/chunk-2NIAOCIC.js.map +0 -1
- package/dist/chunk-3XAB4IXF.js +0 -51
- package/dist/chunk-3XAB4IXF.js.map +0 -1
- package/dist/chunk-6HXKTOD7.js.map +0 -1
- package/dist/chunk-BBCUK6N2.js +0 -241
- package/dist/chunk-BBCUK6N2.js.map +0 -1
- package/dist/chunk-BWGFN44T.js.map +0 -1
- package/dist/chunk-ELK6Q7QI.js +0 -545
- package/dist/chunk-ELK6Q7QI.js.map +0 -1
- package/dist/chunk-JY7R7V4G.js.map +0 -1
- package/dist/chunk-LYSBSZYV.js +0 -1523
- package/dist/chunk-LYSBSZYV.js.map +0 -1
- package/dist/chunk-VIWUCJ4V.js.map +0 -1
- package/dist/chunk-VU4FLXV5.js.map +0 -1
- package/dist/chunk-XP2DXWYP.js.map +0 -1
- package/dist/dashboard/public/assets/index-C7X6LP5Z.css +0 -32
- package/dist/dashboard/public/assets/index-ClYqpcAJ.js +0 -645
- package/dist/feedback-writer-AAKF5BTK.js.map +0 -1
- package/dist/review-status-GWQYY77L.js.map +0 -1
- package/dist/traefik-CUJM6K5Z.js +0 -12
- /package/dist/{agents-BDFHF4T3.js.map → agents-E43Y3HNU.js.map} +0 -0
- /package/dist/{config-BOAMSKTF.js.map → config-4CJNUE3O.js.map} +0 -0
- /package/dist/{dns-L3L2BB27.js.map → dns-7BDJSD3E.js.map} +0 -0
- /package/dist/{projects-VXRUCMLM.js.map → hume-WMAUBBV2.js.map} +0 -0
- /package/dist/{remote-agents-Z3R2A5BN.js.map → projects-JEIVIYC6.js.map} +0 -0
- /package/dist/{specialist-logs-GF3YV4KL.js.map → rally-RKFSWC7E.js.map} +0 -0
- /package/dist/{specialists-JBIW6MP4.js.map → remote-agents-TFSMW7GN.js.map} +0 -0
- /package/dist/{remote-workspace-2G6V2KNP.js.map → remote-workspace-AHVHQEES.js.map} +0 -0
- /package/dist/{traefik-CUJM6K5Z.js.map → review-status-EPFG4XM7.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>
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
detectCrashedAgents,
|
|
5
5
|
getActivity,
|
|
6
6
|
getAgentDir,
|
|
7
|
+
getAgentRuntimeFile,
|
|
7
8
|
getAgentRuntimeState,
|
|
8
9
|
getAgentState,
|
|
9
10
|
getSessionId,
|
|
@@ -17,12 +18,13 @@ import {
|
|
|
17
18
|
saveSessionId,
|
|
18
19
|
spawnAgent,
|
|
19
20
|
stopAgent
|
|
20
|
-
} from "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-
|
|
21
|
+
} from "./chunk-HZT2AOPN.js";
|
|
22
|
+
import "./chunk-FTCPTHIJ.js";
|
|
23
|
+
import "./chunk-NTO3EDB3.js";
|
|
24
|
+
import "./chunk-HJSM6E6U.js";
|
|
25
|
+
import "./chunk-FQ66DECN.js";
|
|
26
|
+
import "./chunk-CFCUOV3Q.js";
|
|
27
|
+
import "./chunk-ZTFNYOC7.js";
|
|
26
28
|
import "./chunk-ZHC57RCV.js";
|
|
27
29
|
init_agents();
|
|
28
30
|
export {
|
|
@@ -31,6 +33,7 @@ export {
|
|
|
31
33
|
detectCrashedAgents,
|
|
32
34
|
getActivity,
|
|
33
35
|
getAgentDir,
|
|
36
|
+
getAgentRuntimeFile,
|
|
34
37
|
getAgentRuntimeState,
|
|
35
38
|
getAgentState,
|
|
36
39
|
getSessionId,
|
|
@@ -44,4 +47,4 @@ export {
|
|
|
44
47
|
spawnAgent,
|
|
45
48
|
stopAgent
|
|
46
49
|
};
|
|
47
|
-
//# sourceMappingURL=agents-
|
|
50
|
+
//# sourceMappingURL=agents-E43Y3HNU.js.map
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_workspace_config,
|
|
3
|
+
replacePlaceholders
|
|
4
|
+
} from "./chunk-CWELWPWQ.js";
|
|
5
|
+
import {
|
|
6
|
+
__esm,
|
|
7
|
+
init_esm_shims
|
|
8
|
+
} from "./chunk-ZHC57RCV.js";
|
|
9
|
+
|
|
10
|
+
// src/lib/hume.ts
|
|
11
|
+
async function humeFetch(path, apiKey, method = "GET", body) {
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT);
|
|
14
|
+
try {
|
|
15
|
+
const resp = await fetch(`${HUME_API}${path}`, {
|
|
16
|
+
method,
|
|
17
|
+
headers: {
|
|
18
|
+
"X-Hume-Api-Key": apiKey,
|
|
19
|
+
"Content-Type": "application/json"
|
|
20
|
+
},
|
|
21
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
22
|
+
signal: controller.signal
|
|
23
|
+
});
|
|
24
|
+
if (resp.status === 204) {
|
|
25
|
+
return { ok: true, status: 204, data: null };
|
|
26
|
+
}
|
|
27
|
+
const json = await resp.json();
|
|
28
|
+
return { ok: resp.ok, status: resp.status, data: json };
|
|
29
|
+
} catch (err) {
|
|
30
|
+
return { ok: false, status: 0, data: { message: err.message } };
|
|
31
|
+
} finally {
|
|
32
|
+
clearTimeout(timeout);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function createHumeConfig(config, placeholders) {
|
|
36
|
+
const steps = [];
|
|
37
|
+
const apiKey = process.env[config.api_key_env || "HUME_API_KEY"];
|
|
38
|
+
if (!apiKey) {
|
|
39
|
+
return { success: false, steps: [`[hume] API key not found in env var ${config.api_key_env || "HUME_API_KEY"}`] };
|
|
40
|
+
}
|
|
41
|
+
const configName = replacePlaceholders(config.name_pattern, placeholders);
|
|
42
|
+
const byollmUrl = replacePlaceholders(config.byollm_url_pattern, placeholders);
|
|
43
|
+
steps.push(`[hume] Target config: ${configName}`);
|
|
44
|
+
steps.push(`[hume] BYOLLM URL: ${byollmUrl}`);
|
|
45
|
+
const listResult = await humeFetch(`/configs?name=${encodeURIComponent(configName)}`, apiKey);
|
|
46
|
+
if (listResult.ok) {
|
|
47
|
+
const configs = listResult.data?.configs_page ?? [];
|
|
48
|
+
const existing = Array.isArray(configs) ? configs.find((c) => c.name === configName) : null;
|
|
49
|
+
if (existing) {
|
|
50
|
+
steps.push(`[hume] Config "${configName}" already exists (ID: ${existing.id}), skipping creation`);
|
|
51
|
+
return { success: true, steps, configId: existing.id, configName };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const templateResult = await humeFetch(`/configs/${config.template_config_id}`, apiKey);
|
|
55
|
+
if (!templateResult.ok) {
|
|
56
|
+
steps.push(`[hume] Failed to get template config ${config.template_config_id}: ${JSON.stringify(templateResult.data)}`);
|
|
57
|
+
return { success: false, steps };
|
|
58
|
+
}
|
|
59
|
+
const templatePage = templateResult.data?.configs_page;
|
|
60
|
+
const template = Array.isArray(templatePage) ? templatePage[0] : templateResult.data;
|
|
61
|
+
if (!template || !template.id) {
|
|
62
|
+
steps.push(`[hume] Template config ${config.template_config_id} not found in response`);
|
|
63
|
+
return { success: false, steps };
|
|
64
|
+
}
|
|
65
|
+
steps.push(`[hume] Read template config: ${template.name || config.template_config_id}`);
|
|
66
|
+
const newConfig = {
|
|
67
|
+
name: configName,
|
|
68
|
+
evi_version: template.evi_version || "3",
|
|
69
|
+
language_model: {
|
|
70
|
+
model_provider: "CUSTOM_LANGUAGE_MODEL",
|
|
71
|
+
model_resource: byollmUrl
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
if (template.voice) {
|
|
75
|
+
newConfig.voice = template.voice;
|
|
76
|
+
}
|
|
77
|
+
if (template.prompt) {
|
|
78
|
+
newConfig.prompt = template.prompt;
|
|
79
|
+
}
|
|
80
|
+
if (template.event_messages) {
|
|
81
|
+
newConfig.event_messages = template.event_messages;
|
|
82
|
+
}
|
|
83
|
+
if (template.timeouts) {
|
|
84
|
+
newConfig.timeouts = template.timeouts;
|
|
85
|
+
}
|
|
86
|
+
if (template.tools) {
|
|
87
|
+
newConfig.tools = template.tools;
|
|
88
|
+
}
|
|
89
|
+
if (template.builtin_tools) {
|
|
90
|
+
newConfig.builtin_tools = template.builtin_tools;
|
|
91
|
+
}
|
|
92
|
+
if (template.ellm_model) {
|
|
93
|
+
newConfig.ellm_model = template.ellm_model;
|
|
94
|
+
}
|
|
95
|
+
const createResult = await humeFetch("/configs", apiKey, "POST", newConfig);
|
|
96
|
+
if (!createResult.ok) {
|
|
97
|
+
steps.push(`[hume] Failed to create config: ${JSON.stringify(createResult.data)}`);
|
|
98
|
+
return { success: false, steps };
|
|
99
|
+
}
|
|
100
|
+
const newId = createResult.data?.id;
|
|
101
|
+
steps.push(`[hume] Created config "${configName}" (ID: ${newId})`);
|
|
102
|
+
return { success: true, steps, configId: newId, configName };
|
|
103
|
+
}
|
|
104
|
+
async function deleteHumeConfig(config, placeholders) {
|
|
105
|
+
const steps = [];
|
|
106
|
+
const apiKey = process.env[config.api_key_env || "HUME_API_KEY"];
|
|
107
|
+
if (!apiKey) {
|
|
108
|
+
return { success: false, steps: [`[hume] API key not found in env var ${config.api_key_env || "HUME_API_KEY"}`] };
|
|
109
|
+
}
|
|
110
|
+
const configName = replacePlaceholders(config.name_pattern, placeholders);
|
|
111
|
+
steps.push(`[hume] Looking for config: ${configName}`);
|
|
112
|
+
const listResult = await humeFetch(`/configs?name=${encodeURIComponent(configName)}`, apiKey);
|
|
113
|
+
if (!listResult.ok) {
|
|
114
|
+
steps.push(`[hume] Failed to list configs: ${JSON.stringify(listResult.data)}`);
|
|
115
|
+
return { success: false, steps };
|
|
116
|
+
}
|
|
117
|
+
const configs = listResult.data?.configs_page ?? [];
|
|
118
|
+
const matches = Array.isArray(configs) ? configs.filter((c) => c.name === configName) : [];
|
|
119
|
+
if (matches.length === 0) {
|
|
120
|
+
steps.push(`[hume] No config found with name "${configName}"`);
|
|
121
|
+
return { success: true, steps };
|
|
122
|
+
}
|
|
123
|
+
let allOk = true;
|
|
124
|
+
for (const match of matches) {
|
|
125
|
+
const delResult = await humeFetch(`/configs/${match.id}`, apiKey, "DELETE");
|
|
126
|
+
if (delResult.ok) {
|
|
127
|
+
steps.push(`[hume] Deleted config "${configName}" (ID: ${match.id})`);
|
|
128
|
+
} else {
|
|
129
|
+
steps.push(`[hume] Failed to delete config ${match.id}: ${JSON.stringify(delResult.data)}`);
|
|
130
|
+
allOk = false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return { success: allOk, steps };
|
|
134
|
+
}
|
|
135
|
+
var HUME_API, FETCH_TIMEOUT;
|
|
136
|
+
var init_hume = __esm({
|
|
137
|
+
"src/lib/hume.ts"() {
|
|
138
|
+
init_esm_shims();
|
|
139
|
+
init_workspace_config();
|
|
140
|
+
HUME_API = "https://api.hume.ai/v0/evi";
|
|
141
|
+
FETCH_TIMEOUT = 15e3;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
export {
|
|
146
|
+
createHumeConfig,
|
|
147
|
+
deleteHumeConfig,
|
|
148
|
+
init_hume
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=chunk-7SN4L4PH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/hume.ts"],"sourcesContent":["/**\n * Hume EVI Config Management\n *\n * Manages per-workspace Hume EVI configs for BYOLLM (Bring Your Own LLM).\n * Called during workspace create (createHumeConfig) and workspace remove/deep-wipe (deleteHumeConfig).\n *\n * Pattern mirrors tunnel.ts — stateless CRUD against external API.\n */\n\nimport { HumeConfig, TemplatePlaceholders, replacePlaceholders } from './workspace-config.js';\n\nexport interface HumeResult {\n success: boolean;\n steps: string[];\n /** Populated on successful create */\n configId?: string;\n configName?: string;\n}\n\nconst HUME_API = 'https://api.hume.ai/v0/evi';\nconst FETCH_TIMEOUT = 15_000;\n\n/**\n * Make an authenticated Hume API request.\n * Auth via X-Hume-Api-Key header.\n */\nasync function humeFetch(\n path: string,\n apiKey: string,\n method: 'GET' | 'POST' | 'DELETE' = 'GET',\n body?: unknown,\n): Promise<{ ok: boolean; status: number; data: any }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT);\n\n try {\n const resp = await fetch(`${HUME_API}${path}`, {\n method,\n headers: {\n 'X-Hume-Api-Key': apiKey,\n 'Content-Type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n // DELETE returns 204 No Content\n if (resp.status === 204) {\n return { ok: true, status: 204, data: null };\n }\n\n const json = await resp.json();\n return { ok: resp.ok, status: resp.status, data: json };\n } catch (err: any) {\n return { ok: false, status: 0, data: { message: err.message } };\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Create a workspace-specific Hume EVI config by cloning the template config.\n *\n * Steps:\n * 1. Resolve config name from name_pattern with placeholders\n * 2. Check if config already exists (idempotent)\n * 3. GET template config to extract voice, prompt, tools, etc.\n * 4. POST new config with workspace-specific BYOLLM URL\n */\nexport async function createHumeConfig(\n config: HumeConfig,\n placeholders: TemplatePlaceholders,\n): Promise<HumeResult> {\n const steps: string[] = [];\n\n // Resolve API key\n const apiKey = process.env[config.api_key_env || 'HUME_API_KEY'];\n if (!apiKey) {\n return { success: false, steps: [`[hume] API key not found in env var ${config.api_key_env || 'HUME_API_KEY'}`] };\n }\n\n // Resolve config name and BYOLLM URL\n const configName = replacePlaceholders(config.name_pattern, placeholders);\n const byollmUrl = replacePlaceholders(config.byollm_url_pattern, placeholders);\n steps.push(`[hume] Target config: ${configName}`);\n steps.push(`[hume] BYOLLM URL: ${byollmUrl}`);\n\n // Check if config already exists (idempotent)\n const listResult = await humeFetch(`/configs?name=${encodeURIComponent(configName)}`, apiKey);\n if (listResult.ok) {\n const configs = listResult.data?.configs_page ?? [];\n const existing = Array.isArray(configs)\n ? configs.find((c: any) => c.name === configName)\n : null;\n if (existing) {\n steps.push(`[hume] Config \"${configName}\" already exists (ID: ${existing.id}), skipping creation`);\n return { success: true, steps, configId: existing.id, configName };\n }\n }\n\n // GET template config (API returns paginated format even for single-config lookup)\n const templateResult = await humeFetch(`/configs/${config.template_config_id}`, apiKey);\n if (!templateResult.ok) {\n steps.push(`[hume] Failed to get template config ${config.template_config_id}: ${JSON.stringify(templateResult.data)}`);\n return { success: false, steps };\n }\n\n // Extract config from paginated response\n const templatePage = templateResult.data?.configs_page;\n const template = Array.isArray(templatePage) ? templatePage[0] : templateResult.data;\n if (!template || !template.id) {\n steps.push(`[hume] Template config ${config.template_config_id} not found in response`);\n return { success: false, steps };\n }\n steps.push(`[hume] Read template config: ${template.name || config.template_config_id}`);\n\n // Build new config payload — clone template but override name and BYOLLM URL\n const newConfig: Record<string, any> = {\n name: configName,\n evi_version: template.evi_version || '3',\n language_model: {\n model_provider: 'CUSTOM_LANGUAGE_MODEL',\n model_resource: byollmUrl,\n },\n };\n\n // Preserve voice from template\n if (template.voice) {\n newConfig.voice = template.voice;\n }\n\n // Preserve prompt from template\n if (template.prompt) {\n newConfig.prompt = template.prompt;\n }\n\n // Preserve event messages from template\n if (template.event_messages) {\n newConfig.event_messages = template.event_messages;\n }\n\n // Preserve timeouts from template\n if (template.timeouts) {\n newConfig.timeouts = template.timeouts;\n }\n\n // Preserve tools from template\n if (template.tools) {\n newConfig.tools = template.tools;\n }\n\n // Preserve builtin_tools from template\n if (template.builtin_tools) {\n newConfig.builtin_tools = template.builtin_tools;\n }\n\n // Preserve ellm_model (quick responses) from template\n if (template.ellm_model) {\n newConfig.ellm_model = template.ellm_model;\n }\n\n // Create new config\n const createResult = await humeFetch('/configs', apiKey, 'POST', newConfig);\n if (!createResult.ok) {\n steps.push(`[hume] Failed to create config: ${JSON.stringify(createResult.data)}`);\n return { success: false, steps };\n }\n\n const newId = createResult.data?.id;\n steps.push(`[hume] Created config \"${configName}\" (ID: ${newId})`);\n\n return { success: true, steps, configId: newId, configName };\n}\n\n/**\n * Delete a workspace-specific Hume EVI config.\n *\n * Steps:\n * 1. List configs matching the workspace name\n * 2. DELETE each match\n */\nexport async function deleteHumeConfig(\n config: HumeConfig,\n placeholders: TemplatePlaceholders,\n): Promise<HumeResult> {\n const steps: string[] = [];\n\n // Resolve API key\n const apiKey = process.env[config.api_key_env || 'HUME_API_KEY'];\n if (!apiKey) {\n return { success: false, steps: [`[hume] API key not found in env var ${config.api_key_env || 'HUME_API_KEY'}`] };\n }\n\n const configName = replacePlaceholders(config.name_pattern, placeholders);\n steps.push(`[hume] Looking for config: ${configName}`);\n\n // List configs matching the name\n const listResult = await humeFetch(`/configs?name=${encodeURIComponent(configName)}`, apiKey);\n if (!listResult.ok) {\n steps.push(`[hume] Failed to list configs: ${JSON.stringify(listResult.data)}`);\n return { success: false, steps };\n }\n\n const configs = listResult.data?.configs_page ?? [];\n const matches = Array.isArray(configs)\n ? configs.filter((c: any) => c.name === configName)\n : [];\n\n if (matches.length === 0) {\n steps.push(`[hume] No config found with name \"${configName}\"`);\n return { success: true, steps };\n }\n\n let allOk = true;\n for (const match of matches) {\n const delResult = await humeFetch(`/configs/${match.id}`, apiKey, 'DELETE');\n if (delResult.ok) {\n steps.push(`[hume] Deleted config \"${configName}\" (ID: ${match.id})`);\n } else {\n steps.push(`[hume] Failed to delete config ${match.id}: ${JSON.stringify(delResult.data)}`);\n allOk = false;\n }\n }\n\n return { success: allOk, steps };\n}\n"],"mappings":"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","names":[]}
|