panopticon-cli 0.1.3 → 0.1.6

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/dist/index.d.ts CHANGED
@@ -5,6 +5,10 @@ declare const COMMANDS_DIR: string;
5
5
  declare const AGENTS_DIR: string;
6
6
  declare const BACKUPS_DIR: string;
7
7
  declare const COSTS_DIR: string;
8
+ declare const TRAEFIK_DIR: string;
9
+ declare const TRAEFIK_DYNAMIC_DIR: string;
10
+ declare const TRAEFIK_CERTS_DIR: string;
11
+ declare const CERTS_DIR: string;
8
12
  declare const CONFIG_FILE: string;
9
13
  declare const CLAUDE_DIR: string;
10
14
  declare const CODEX_DIR: string;
@@ -31,8 +35,174 @@ declare const SYNC_TARGETS: {
31
35
  type Runtime = keyof typeof SYNC_TARGETS;
32
36
  declare const TEMPLATES_DIR: string;
33
37
  declare const CLAUDE_MD_TEMPLATES: string;
38
+ declare const SOURCE_TEMPLATES_DIR: string;
39
+ declare const SOURCE_TRAEFIK_TEMPLATES: string;
34
40
  declare const INIT_DIRS: string[];
35
41
 
42
+ /**
43
+ * Issue Tracker Abstraction Layer
44
+ *
45
+ * Provides a unified interface for different issue tracking systems
46
+ * (Linear, GitHub Issues, GitLab Issues, etc.)
47
+ */
48
+ type TrackerType = 'linear' | 'github' | 'gitlab';
49
+ type IssueState = 'open' | 'in_progress' | 'closed';
50
+ interface Issue {
51
+ /** Tracker-specific unique ID */
52
+ id: string;
53
+ /** Human-readable reference (e.g., MIN-630, #42) */
54
+ ref: string;
55
+ /** Issue title */
56
+ title: string;
57
+ /** Issue description/body (markdown) */
58
+ description: string;
59
+ /** Normalized state */
60
+ state: IssueState;
61
+ /** Labels/tags */
62
+ labels: string[];
63
+ /** Assignee username/name */
64
+ assignee?: string;
65
+ /** Web URL to the issue */
66
+ url: string;
67
+ /** Which tracker this issue came from */
68
+ tracker: TrackerType;
69
+ /** Cross-tracker linked issue references */
70
+ linkedIssues?: string[];
71
+ /** Priority (1=urgent, 2=high, 3=normal, 4=low) */
72
+ priority?: number;
73
+ /** Due date (ISO string) */
74
+ dueDate?: string;
75
+ /** Creation timestamp (ISO string) */
76
+ createdAt: string;
77
+ /** Last update timestamp (ISO string) */
78
+ updatedAt: string;
79
+ }
80
+ interface Comment {
81
+ id: string;
82
+ issueId: string;
83
+ body: string;
84
+ author: string;
85
+ createdAt: string;
86
+ updatedAt: string;
87
+ }
88
+ interface IssueFilters {
89
+ /** Filter by state */
90
+ state?: IssueState;
91
+ /** Filter by labels (AND logic) */
92
+ labels?: string[];
93
+ /** Filter by assignee */
94
+ assignee?: string;
95
+ /** Filter by team/project (tracker-specific) */
96
+ team?: string;
97
+ /** Search query for title/description */
98
+ query?: string;
99
+ /** Maximum number of results */
100
+ limit?: number;
101
+ /** Include closed issues (default: false) */
102
+ includeClosed?: boolean;
103
+ }
104
+ interface NewIssue {
105
+ title: string;
106
+ description?: string;
107
+ labels?: string[];
108
+ assignee?: string;
109
+ team?: string;
110
+ priority?: number;
111
+ dueDate?: string;
112
+ }
113
+ interface IssueUpdate {
114
+ title?: string;
115
+ description?: string;
116
+ state?: IssueState;
117
+ labels?: string[];
118
+ assignee?: string;
119
+ priority?: number;
120
+ dueDate?: string;
121
+ }
122
+ /**
123
+ * Abstract interface for issue trackers.
124
+ * Implementations must handle normalization to/from tracker-specific formats.
125
+ */
126
+ interface IssueTracker {
127
+ /** Tracker type identifier */
128
+ readonly name: TrackerType;
129
+ /**
130
+ * List issues matching filters
131
+ */
132
+ listIssues(filters?: IssueFilters): Promise<Issue[]>;
133
+ /**
134
+ * Get a single issue by ID or ref
135
+ * @param id - Issue ID or human-readable ref (e.g., "MIN-630", "#42")
136
+ */
137
+ getIssue(id: string): Promise<Issue>;
138
+ /**
139
+ * Update an existing issue
140
+ */
141
+ updateIssue(id: string, update: IssueUpdate): Promise<Issue>;
142
+ /**
143
+ * Create a new issue
144
+ */
145
+ createIssue(issue: NewIssue): Promise<Issue>;
146
+ /**
147
+ * Get comments on an issue
148
+ */
149
+ getComments(issueId: string): Promise<Comment[]>;
150
+ /**
151
+ * Add a comment to an issue
152
+ */
153
+ addComment(issueId: string, body: string): Promise<Comment>;
154
+ /**
155
+ * Transition issue to a new state
156
+ */
157
+ transitionIssue(id: string, state: IssueState): Promise<void>;
158
+ /**
159
+ * Link a PR/MR to an issue
160
+ */
161
+ linkPR(issueId: string, prUrl: string): Promise<void>;
162
+ }
163
+ /**
164
+ * Error thrown when a tracker feature is not implemented
165
+ */
166
+ declare class NotImplementedError extends Error {
167
+ constructor(feature: string);
168
+ }
169
+ /**
170
+ * Error thrown when an issue is not found
171
+ */
172
+ declare class IssueNotFoundError extends Error {
173
+ constructor(id: string, tracker: TrackerType);
174
+ }
175
+ /**
176
+ * Error thrown when tracker authentication fails
177
+ */
178
+ declare class TrackerAuthError extends Error {
179
+ constructor(tracker: TrackerType, message: string);
180
+ }
181
+
182
+ interface LinearConfig {
183
+ type: 'linear';
184
+ api_key_env?: string;
185
+ team?: string;
186
+ }
187
+ interface GitHubConfig {
188
+ type: 'github';
189
+ token_env?: string;
190
+ owner: string;
191
+ repo: string;
192
+ }
193
+ interface GitLabConfig {
194
+ type: 'gitlab';
195
+ token_env?: string;
196
+ project_id: string;
197
+ }
198
+ type TrackerConfigItem = LinearConfig | GitHubConfig | GitLabConfig;
199
+ interface TrackersConfig {
200
+ primary: TrackerType;
201
+ secondary?: TrackerType;
202
+ linear?: LinearConfig;
203
+ github?: GitHubConfig;
204
+ gitlab?: GitLabConfig;
205
+ }
36
206
  interface PanopticonConfig {
37
207
  panopticon: {
38
208
  version: string;
@@ -40,15 +210,19 @@ interface PanopticonConfig {
40
210
  sync: {
41
211
  targets: string[];
42
212
  backup_before_sync: boolean;
213
+ auto_sync?: boolean;
214
+ strategy?: 'symlink' | 'copy';
43
215
  };
44
- trackers: {
45
- primary: string;
46
- secondary?: string;
47
- };
216
+ trackers: TrackersConfig;
48
217
  dashboard: {
49
218
  port: number;
50
219
  api_port: number;
51
220
  };
221
+ traefik?: {
222
+ enabled: boolean;
223
+ dashboard_port?: number;
224
+ domain?: string;
225
+ };
52
226
  }
53
227
  declare function loadConfig(): PanopticonConfig;
54
228
  declare function saveConfig(config: PanopticonConfig): void;
@@ -105,4 +279,193 @@ interface SyncResult {
105
279
  */
106
280
  declare function executeSync(runtime: Runtime, options?: SyncOptions): SyncResult;
107
281
 
108
- export { AGENTS_DIR, BACKUPS_DIR, type BackupInfo, CLAUDE_DIR, CLAUDE_MD_TEMPLATES, CODEX_DIR, COMMANDS_DIR, CONFIG_DIR, CONFIG_FILE, COSTS_DIR, CURSOR_DIR, GEMINI_DIR, INIT_DIRS, PANOPTICON_HOME, type PanopticonConfig, type Runtime, SKILLS_DIR, SYNC_TARGETS, type Shell, type SyncItem, type SyncOptions, type SyncPlan, type SyncResult, TEMPLATES_DIR, addAlias, cleanOldBackups, createBackup, createBackupTimestamp, detectShell, executeSync, getAliasInstructions, getDefaultConfig, getShellRcFile, hasAlias, isPanopticonSymlink, listBackups, loadConfig, planSync, restoreBackup, saveConfig };
282
+ /**
283
+ * Linear Issue Tracker Adapter
284
+ *
285
+ * Implements IssueTracker interface for Linear.
286
+ */
287
+
288
+ declare class LinearTracker implements IssueTracker {
289
+ readonly name: TrackerType;
290
+ private client;
291
+ private defaultTeam?;
292
+ constructor(apiKey: string, options?: {
293
+ team?: string;
294
+ });
295
+ listIssues(filters?: IssueFilters): Promise<Issue[]>;
296
+ getIssue(id: string): Promise<Issue>;
297
+ updateIssue(id: string, update: IssueUpdate): Promise<Issue>;
298
+ createIssue(newIssue: NewIssue): Promise<Issue>;
299
+ getComments(issueId: string): Promise<Comment[]>;
300
+ addComment(issueId: string, body: string): Promise<Comment>;
301
+ transitionIssue(id: string, state: IssueState): Promise<void>;
302
+ linkPR(issueId: string, prUrl: string): Promise<void>;
303
+ private normalizeIssue;
304
+ private mapState;
305
+ private reverseMapState;
306
+ }
307
+
308
+ /**
309
+ * GitHub Issues Tracker Adapter
310
+ *
311
+ * Implements IssueTracker interface for GitHub Issues.
312
+ */
313
+
314
+ declare class GitHubTracker implements IssueTracker {
315
+ readonly name: TrackerType;
316
+ private octokit;
317
+ private owner;
318
+ private repo;
319
+ constructor(token: string, owner: string, repo: string);
320
+ listIssues(filters?: IssueFilters): Promise<Issue[]>;
321
+ getIssue(id: string): Promise<Issue>;
322
+ updateIssue(id: string, update: IssueUpdate): Promise<Issue>;
323
+ createIssue(newIssue: NewIssue): Promise<Issue>;
324
+ getComments(issueId: string): Promise<Comment[]>;
325
+ addComment(issueId: string, body: string): Promise<Comment>;
326
+ transitionIssue(id: string, state: IssueState): Promise<void>;
327
+ linkPR(issueId: string, prUrl: string): Promise<void>;
328
+ private normalizeIssue;
329
+ private mapStateFromGitHub;
330
+ private mapStateToGitHub;
331
+ }
332
+
333
+ /**
334
+ * GitLab Issues Tracker Adapter (Stub)
335
+ *
336
+ * Placeholder implementation for GitLab Issues support.
337
+ * Full implementation will use @gitbeaker/rest.
338
+ */
339
+
340
+ declare class GitLabTracker implements IssueTracker {
341
+ private token;
342
+ private projectId;
343
+ readonly name: TrackerType;
344
+ constructor(token: string, projectId: string);
345
+ listIssues(_filters?: IssueFilters): Promise<Issue[]>;
346
+ getIssue(_id: string): Promise<Issue>;
347
+ updateIssue(_id: string, _update: IssueUpdate): Promise<Issue>;
348
+ createIssue(_issue: NewIssue): Promise<Issue>;
349
+ getComments(_issueId: string): Promise<Comment[]>;
350
+ addComment(_issueId: string, _body: string): Promise<Comment>;
351
+ transitionIssue(_id: string, _state: IssueState): Promise<void>;
352
+ linkPR(_issueId: string, _prUrl: string): Promise<void>;
353
+ }
354
+
355
+ /**
356
+ * Tracker Factory
357
+ *
358
+ * Creates appropriate tracker instances based on configuration.
359
+ */
360
+
361
+ interface TrackerConfig {
362
+ type: TrackerType;
363
+ apiKeyEnv?: string;
364
+ team?: string;
365
+ tokenEnv?: string;
366
+ owner?: string;
367
+ repo?: string;
368
+ projectId?: string;
369
+ }
370
+ /**
371
+ * Create a tracker instance from configuration
372
+ */
373
+ declare function createTracker(config: TrackerConfig): IssueTracker;
374
+ /**
375
+ * Create tracker from trackers configuration section
376
+ */
377
+ declare function createTrackerFromConfig(trackersConfig: TrackersConfig, trackerType: TrackerType): IssueTracker;
378
+ /**
379
+ * Get the primary tracker from configuration
380
+ */
381
+ declare function getPrimaryTracker(trackersConfig: TrackersConfig): IssueTracker;
382
+ /**
383
+ * Get the secondary tracker from configuration (if configured)
384
+ */
385
+ declare function getSecondaryTracker(trackersConfig: TrackersConfig): IssueTracker | null;
386
+ /**
387
+ * Get all configured trackers
388
+ */
389
+ declare function getAllTrackers(trackersConfig: TrackersConfig): IssueTracker[];
390
+
391
+ /**
392
+ * Cross-Tracker Linking
393
+ *
394
+ * Manages links between issues in different trackers.
395
+ * Links are stored in a local JSON file for persistence.
396
+ */
397
+
398
+ type LinkDirection = 'blocks' | 'blocked_by' | 'related' | 'duplicate_of';
399
+ interface TrackerLink {
400
+ sourceIssueRef: string;
401
+ sourceTracker: TrackerType;
402
+ targetIssueRef: string;
403
+ targetTracker: TrackerType;
404
+ direction: LinkDirection;
405
+ createdAt: string;
406
+ }
407
+ /**
408
+ * Parse an issue reference to extract tracker and ID
409
+ * Examples:
410
+ * "#42" -> { tracker: "github", ref: "#42" }
411
+ * "github#42" -> { tracker: "github", ref: "#42" }
412
+ * "MIN-630" -> { tracker: "linear", ref: "MIN-630" }
413
+ * "gitlab#15" -> { tracker: "gitlab", ref: "#15" }
414
+ */
415
+ declare function parseIssueRef(ref: string): {
416
+ tracker: TrackerType;
417
+ ref: string;
418
+ } | null;
419
+ /**
420
+ * Format an issue ref with tracker prefix for display
421
+ */
422
+ declare function formatIssueRef(ref: string, tracker: TrackerType): string;
423
+ /**
424
+ * Link Manager for cross-tracker issue linking
425
+ */
426
+ declare class LinkManager {
427
+ private storePath;
428
+ private store;
429
+ constructor(storePath?: string);
430
+ private load;
431
+ private save;
432
+ /**
433
+ * Add a link between two issues
434
+ */
435
+ addLink(source: {
436
+ ref: string;
437
+ tracker: TrackerType;
438
+ }, target: {
439
+ ref: string;
440
+ tracker: TrackerType;
441
+ }, direction?: LinkDirection): TrackerLink;
442
+ /**
443
+ * Remove a link between two issues
444
+ */
445
+ removeLink(source: {
446
+ ref: string;
447
+ tracker: TrackerType;
448
+ }, target: {
449
+ ref: string;
450
+ tracker: TrackerType;
451
+ }): boolean;
452
+ /**
453
+ * Get all issues linked to a given issue
454
+ */
455
+ getLinkedIssues(ref: string, tracker: TrackerType): TrackerLink[];
456
+ /**
457
+ * Get all links (for debugging/admin)
458
+ */
459
+ getAllLinks(): TrackerLink[];
460
+ /**
461
+ * Find linked issue in another tracker
462
+ */
463
+ findLinkedIssue(ref: string, sourceTracker: TrackerType, targetTracker: TrackerType): string | null;
464
+ /**
465
+ * Clear all links (for testing)
466
+ */
467
+ clear(): void;
468
+ }
469
+ declare function getLinkManager(): LinkManager;
470
+
471
+ export { AGENTS_DIR, BACKUPS_DIR, type BackupInfo, CERTS_DIR, CLAUDE_DIR, CLAUDE_MD_TEMPLATES, CODEX_DIR, COMMANDS_DIR, CONFIG_DIR, CONFIG_FILE, COSTS_DIR, CURSOR_DIR, type Comment, GEMINI_DIR, type GitHubConfig, GitHubTracker, type GitLabConfig, GitLabTracker, INIT_DIRS, type Issue, type IssueFilters, IssueNotFoundError, type IssueState, type IssueTracker, type IssueUpdate, type LinearConfig, LinearTracker, type LinkDirection, LinkManager, type NewIssue, NotImplementedError, PANOPTICON_HOME, type PanopticonConfig, type Runtime, SKILLS_DIR, SOURCE_TEMPLATES_DIR, SOURCE_TRAEFIK_TEMPLATES, SYNC_TARGETS, type Shell, type SyncItem, type SyncOptions, type SyncPlan, type SyncResult, TEMPLATES_DIR, TRAEFIK_CERTS_DIR, TRAEFIK_DIR, TRAEFIK_DYNAMIC_DIR, TrackerAuthError, type TrackerConfig, type TrackerConfigItem, type TrackerLink, type TrackerType, type TrackersConfig, addAlias, cleanOldBackups, createBackup, createBackupTimestamp, createTracker, createTrackerFromConfig, detectShell, executeSync, formatIssueRef, getAliasInstructions, getAllTrackers, getDefaultConfig, getLinkManager, getPrimaryTracker, getSecondaryTracker, getShellRcFile, hasAlias, isPanopticonSymlink, listBackups, loadConfig, parseIssueRef, planSync, restoreBackup, saveConfig };
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  AGENTS_DIR,
3
3
  BACKUPS_DIR,
4
+ CERTS_DIR,
4
5
  CLAUDE_DIR,
5
6
  CLAUDE_MD_TEMPLATES,
6
7
  CODEX_DIR,
@@ -10,31 +11,52 @@ import {
10
11
  COSTS_DIR,
11
12
  CURSOR_DIR,
12
13
  GEMINI_DIR,
14
+ GitHubTracker,
15
+ GitLabTracker,
13
16
  INIT_DIRS,
17
+ IssueNotFoundError,
18
+ LinearTracker,
19
+ LinkManager,
20
+ NotImplementedError,
14
21
  PANOPTICON_HOME,
15
22
  SKILLS_DIR,
23
+ SOURCE_TEMPLATES_DIR,
24
+ SOURCE_TRAEFIK_TEMPLATES,
16
25
  SYNC_TARGETS,
17
26
  TEMPLATES_DIR,
27
+ TRAEFIK_CERTS_DIR,
28
+ TRAEFIK_DIR,
29
+ TRAEFIK_DYNAMIC_DIR,
30
+ TrackerAuthError,
18
31
  addAlias,
19
32
  cleanOldBackups,
20
33
  createBackup,
21
34
  createBackupTimestamp,
35
+ createTracker,
36
+ createTrackerFromConfig,
22
37
  detectShell,
23
38
  executeSync,
39
+ formatIssueRef,
24
40
  getAliasInstructions,
41
+ getAllTrackers,
25
42
  getDefaultConfig,
43
+ getLinkManager,
44
+ getPrimaryTracker,
45
+ getSecondaryTracker,
26
46
  getShellRcFile,
27
47
  hasAlias,
28
48
  isPanopticonSymlink,
29
49
  listBackups,
30
50
  loadConfig,
51
+ parseIssueRef,
31
52
  planSync,
32
53
  restoreBackup,
33
54
  saveConfig
34
- } from "./chunk-FR2P66GU.js";
55
+ } from "./chunk-RM3WGTFO.js";
35
56
  export {
36
57
  AGENTS_DIR,
37
58
  BACKUPS_DIR,
59
+ CERTS_DIR,
38
60
  CLAUDE_DIR,
39
61
  CLAUDE_MD_TEMPLATES,
40
62
  CODEX_DIR,
@@ -44,24 +66,44 @@ export {
44
66
  COSTS_DIR,
45
67
  CURSOR_DIR,
46
68
  GEMINI_DIR,
69
+ GitHubTracker,
70
+ GitLabTracker,
47
71
  INIT_DIRS,
72
+ IssueNotFoundError,
73
+ LinearTracker,
74
+ LinkManager,
75
+ NotImplementedError,
48
76
  PANOPTICON_HOME,
49
77
  SKILLS_DIR,
78
+ SOURCE_TEMPLATES_DIR,
79
+ SOURCE_TRAEFIK_TEMPLATES,
50
80
  SYNC_TARGETS,
51
81
  TEMPLATES_DIR,
82
+ TRAEFIK_CERTS_DIR,
83
+ TRAEFIK_DIR,
84
+ TRAEFIK_DYNAMIC_DIR,
85
+ TrackerAuthError,
52
86
  addAlias,
53
87
  cleanOldBackups,
54
88
  createBackup,
55
89
  createBackupTimestamp,
90
+ createTracker,
91
+ createTrackerFromConfig,
56
92
  detectShell,
57
93
  executeSync,
94
+ formatIssueRef,
58
95
  getAliasInstructions,
96
+ getAllTrackers,
59
97
  getDefaultConfig,
98
+ getLinkManager,
99
+ getPrimaryTracker,
100
+ getSecondaryTracker,
60
101
  getShellRcFile,
61
102
  hasAlias,
62
103
  isPanopticonSymlink,
63
104
  listBackups,
64
105
  loadConfig,
106
+ parseIssueRef,
65
107
  planSync,
66
108
  restoreBackup,
67
109
  saveConfig
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "panopticon-cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.6",
4
4
  "description": "Multi-agent orchestration for AI coding assistants (Claude Code, Codex, Cursor, Gemini CLI)",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -50,6 +50,7 @@
50
50
  "dependencies": {
51
51
  "@iarna/toml": "^2.2.5",
52
52
  "@linear/sdk": "^70.0.0",
53
+ "@octokit/rest": "^22.0.1",
53
54
  "chalk": "^5.6.2",
54
55
  "commander": "^12.1.0",
55
56
  "conf": "^12.0.0",
@@ -0,0 +1,106 @@
1
+ # Panopticon Traefik Configuration
2
+
3
+ Traefik reverse proxy for local development with HTTPS.
4
+
5
+ ## Directory Structure
6
+
7
+ ```
8
+ ~/.panopticon/traefik/
9
+ ├── docker-compose.yml # Traefik container definition
10
+ ├── traefik.yml # Static configuration
11
+ ├── dynamic/ # Dynamic routing configs
12
+ │ └── panopticon.yml # Dashboard routing
13
+ ├── certs/ # mkcert SSL certificates
14
+ │ ├── _wildcard.pan.localhost.pem
15
+ │ └── _wildcard.pan.localhost-key.pem
16
+ └── README.md # This file
17
+ ```
18
+
19
+ ## URLs
20
+
21
+ | URL | Service |
22
+ |-----|---------|
23
+ | `https://pan.localhost` | Panopticon Dashboard (Frontend) |
24
+ | `https://pan.localhost/api/*` | Panopticon Dashboard (API) |
25
+ | `http://localhost:8080` | Traefik Dashboard |
26
+
27
+ ## How It Works
28
+
29
+ ### Static Configuration (`traefik.yml`)
30
+ - Defines entry points (HTTP:80, HTTPS:443)
31
+ - Enables Traefik dashboard on port 8080
32
+ - Configures file provider for dynamic configs
33
+ - Sets up TLS with wildcard certificates
34
+
35
+ ### Dynamic Configuration (`dynamic/panopticon.yml`)
36
+ - Routes `https://pan.localhost` to dashboard frontend (port 3001)
37
+ - Routes `https://pan.localhost/api/*` to dashboard API (port 3002)
38
+ - Uses `host.docker.internal` to access host-based services
39
+
40
+ ### Docker Compose
41
+ - Runs Traefik v3.0 in a container
42
+ - Exposes ports 80, 443, 8080
43
+ - Mounts configuration files and certificates
44
+ - Uses `panopticon` network for container communication
45
+
46
+ ## Prerequisites
47
+
48
+ 1. **mkcert certificates** must be generated first:
49
+ ```bash
50
+ mkcert "*.pan.localhost" "*.localhost" localhost 127.0.0.1 ::1
51
+ ```
52
+ Certificates should be in `~/.panopticon/traefik/certs/`
53
+
54
+ 2. **DNS/Hosts configuration**:
55
+ - Add to `/etc/hosts`: `127.0.0.1 pan.localhost`
56
+ - Wildcard `*.localhost` resolves automatically on most systems
57
+
58
+ ## Usage
59
+
60
+ Start Traefik:
61
+ ```bash
62
+ cd ~/.panopticon/traefik
63
+ docker-compose up -d
64
+ ```
65
+
66
+ Stop Traefik:
67
+ ```bash
68
+ cd ~/.panopticon/traefik
69
+ docker-compose down
70
+ ```
71
+
72
+ View logs:
73
+ ```bash
74
+ docker logs -f panopticon-traefik
75
+ ```
76
+
77
+ ## Managed by CLI
78
+
79
+ These commands are automated via `pan` CLI:
80
+ - `pan install` - Sets up Traefik (creates configs, generates certs)
81
+ - `pan up` - Starts Traefik container
82
+ - `pan down` - Stops Traefik container
83
+
84
+ ## Adding Workspace Routes
85
+
86
+ Workspace-specific routes should be added as separate YAML files in `dynamic/`:
87
+
88
+ ```yaml
89
+ # dynamic/feature-pan-4.yml
90
+ http:
91
+ routers:
92
+ workspace-feature-pan-4-frontend:
93
+ rule: "Host(`feature-pan-4.myn.localhost`)"
94
+ service: workspace-feature-pan-4-frontend
95
+ entryPoints:
96
+ - websecure
97
+ tls: {}
98
+
99
+ services:
100
+ workspace-feature-pan-4-frontend:
101
+ loadBalancer:
102
+ servers:
103
+ - url: "http://workspace-feature-pan-4-frontend:3000"
104
+ ```
105
+
106
+ These are auto-generated by `pan workspace create` and `pan workspace start`.
@@ -0,0 +1,40 @@
1
+ services:
2
+ traefik:
3
+ image: traefik:v3.0
4
+ container_name: panopticon-traefik
5
+ restart: unless-stopped
6
+ ports:
7
+ - "8081:80" # HTTP (redirects to HTTPS)
8
+ - "8443:443" # HTTPS
9
+ - "8082:8080" # Traefik Dashboard
10
+ volumes:
11
+ # Traefik configuration
12
+ - ./traefik.yml:/etc/traefik/traefik.yml:ro
13
+ - ./dynamic:/etc/traefik/dynamic:ro
14
+
15
+ # TLS certificates (mkcert generated)
16
+ - ./certs:/etc/traefik/certs:ro
17
+
18
+ # Docker socket for service discovery
19
+ - /var/run/docker.sock:/var/run/docker.sock:ro
20
+
21
+ networks:
22
+ - panopticon
23
+
24
+ labels:
25
+ - "traefik.enable=true"
26
+
27
+ # Dashboard routing (traefik.pan.localhost:8080)
28
+ - "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.pan.localhost`)"
29
+ - "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
30
+ - "traefik.http.routers.traefik-dashboard.tls=true"
31
+ - "traefik.http.routers.traefik-dashboard.service=api@internal"
32
+
33
+ extra_hosts:
34
+ # Allow Traefik to reach host services (dashboard on ports 3001/3002)
35
+ - "host.docker.internal:host-gateway"
36
+
37
+ networks:
38
+ panopticon:
39
+ name: panopticon
40
+ driver: bridge