panopticon-cli 0.1.3 → 0.2.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.
Files changed (37) hide show
  1. package/README.md +645 -22
  2. package/dist/chunk-J7JUNJGH.js +1058 -0
  3. package/dist/chunk-J7JUNJGH.js.map +1 -0
  4. package/dist/cli/index.js +1733 -717
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/index.d.ts +368 -5
  7. package/dist/index.js +43 -1
  8. package/package.json +11 -2
  9. package/templates/context/CLAUDE.md.template +81 -0
  10. package/templates/context/STATE.md.template +106 -0
  11. package/templates/context/WORKSPACE.md.template +90 -0
  12. package/templates/docker/dotnet/Dockerfile.dev +22 -0
  13. package/templates/docker/dotnet/README.md +111 -0
  14. package/templates/docker/dotnet/docker-compose.yml +55 -0
  15. package/templates/docker/monorepo/Dockerfile.backend +15 -0
  16. package/templates/docker/monorepo/Dockerfile.frontend +17 -0
  17. package/templates/docker/monorepo/README.md +208 -0
  18. package/templates/docker/monorepo/docker-compose.yml +88 -0
  19. package/templates/docker/nextjs/Dockerfile.dev +20 -0
  20. package/templates/docker/nextjs/README.md +103 -0
  21. package/templates/docker/nextjs/docker-compose.yml +30 -0
  22. package/templates/docker/python-fastapi/Dockerfile.dev +22 -0
  23. package/templates/docker/python-fastapi/README.md +148 -0
  24. package/templates/docker/python-fastapi/docker-compose.yml +65 -0
  25. package/templates/docker/react-vite/Dockerfile.dev +20 -0
  26. package/templates/docker/react-vite/README.md +94 -0
  27. package/templates/docker/react-vite/docker-compose.yml +29 -0
  28. package/templates/docker/spring-boot/Dockerfile.dev +24 -0
  29. package/templates/docker/spring-boot/README.md +111 -0
  30. package/templates/docker/spring-boot/docker-compose.yml +71 -0
  31. package/templates/traefik/README.md +106 -0
  32. package/templates/traefik/docker-compose.yml +40 -0
  33. package/templates/traefik/dynamic/panopticon.yml +51 -0
  34. package/templates/traefik/dynamic/workspace.yml.template +34 -0
  35. package/templates/traefik/traefik.yml +45 -0
  36. package/dist/chunk-FR2P66GU.js +0 -352
  37. package/dist/chunk-FR2P66GU.js.map +0 -1
@@ -0,0 +1,71 @@
1
+ version: '3.8'
2
+
3
+ services:
4
+ app:
5
+ build:
6
+ context: .
7
+ dockerfile: Dockerfile.dev
8
+ ports:
9
+ - "${APP_PORT:-8080}:8080"
10
+ - "${DEBUG_PORT:-5005}:5005"
11
+ volumes:
12
+ - .:/app
13
+ - maven-cache:/root/.m2
14
+ environment:
15
+ - SPRING_PROFILES_ACTIVE=dev
16
+ - SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/${DB_NAME:-appdb}
17
+ - SPRING_DATASOURCE_USERNAME=${DB_USER:-postgres}
18
+ - SPRING_DATASOURCE_PASSWORD=${DB_PASSWORD:-postgres}
19
+ - SPRING_REDIS_HOST=redis
20
+ - SPRING_REDIS_PORT=6379
21
+ depends_on:
22
+ postgres:
23
+ condition: service_healthy
24
+ redis:
25
+ condition: service_started
26
+ networks:
27
+ - app-network
28
+ labels:
29
+ - "traefik.enable=true"
30
+ - "traefik.http.routers.${COMPOSE_PROJECT_NAME:-app}.rule=Host(`${HOSTNAME:-app.pan.localhost}`)"
31
+ - "traefik.http.services.${COMPOSE_PROJECT_NAME:-app}.loadbalancer.server.port=8080"
32
+
33
+ postgres:
34
+ image: postgres:16-alpine
35
+ environment:
36
+ - POSTGRES_DB=${DB_NAME:-appdb}
37
+ - POSTGRES_USER=${DB_USER:-postgres}
38
+ - POSTGRES_PASSWORD=${DB_PASSWORD:-postgres}
39
+ volumes:
40
+ - postgres-data:/var/lib/postgresql/data
41
+ ports:
42
+ - "${DB_PORT:-5432}:5432"
43
+ healthcheck:
44
+ test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres}"]
45
+ interval: 5s
46
+ timeout: 5s
47
+ retries: 5
48
+ networks:
49
+ - app-network
50
+
51
+ redis:
52
+ image: redis:7-alpine
53
+ ports:
54
+ - "${REDIS_PORT:-6379}:6379"
55
+ volumes:
56
+ - redis-data:/data
57
+ networks:
58
+ - app-network
59
+
60
+ volumes:
61
+ postgres-data:
62
+ redis-data:
63
+ maven-cache:
64
+
65
+ networks:
66
+ app-network:
67
+ driver: bridge
68
+ # Connect to Traefik network if available
69
+ traefik:
70
+ external: true
71
+ name: traefik_default
@@ -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
@@ -0,0 +1,51 @@
1
+ # Dynamic routing configuration for Panopticon Dashboard
2
+ # Routes traffic from pan.localhost to host-based services
3
+
4
+ http:
5
+ routers:
6
+ # Dashboard Frontend (pan.localhost)
7
+ panopticon-frontend:
8
+ rule: "Host(`pan.localhost`) && !PathPrefix(`/api`)"
9
+ entryPoints:
10
+ - websecure
11
+ service: panopticon-frontend
12
+ tls:
13
+ domains:
14
+ - main: "pan.localhost"
15
+ sans:
16
+ - "*.pan.localhost"
17
+
18
+ # Dashboard API (pan.localhost/api/*)
19
+ panopticon-api:
20
+ rule: "Host(`pan.localhost`) && PathPrefix(`/api`)"
21
+ entryPoints:
22
+ - websecure
23
+ service: panopticon-api
24
+ middlewares:
25
+ - api-stripprefix
26
+ tls: {}
27
+
28
+ services:
29
+ # Frontend service (running on host:3001)
30
+ panopticon-frontend:
31
+ loadBalancer:
32
+ servers:
33
+ - url: "http://host.docker.internal:3001"
34
+
35
+ # API service (running on host:3002)
36
+ panopticon-api:
37
+ loadBalancer:
38
+ servers:
39
+ - url: "http://host.docker.internal:3002"
40
+
41
+ middlewares:
42
+ # Strip /api prefix before forwarding to API service
43
+ api-stripprefix:
44
+ stripPrefix:
45
+ prefixes:
46
+ - "/api"
47
+
48
+ tls:
49
+ certificates:
50
+ - certFile: /etc/traefik/certs/_wildcard.pan.localhost.pem
51
+ keyFile: /etc/traefik/certs/_wildcard.pan.localhost-key.pem
@@ -0,0 +1,34 @@
1
+ # Workspace Routing Template
2
+ # This template is used to generate dynamic configs for workspaces
3
+ # Variables: {{WORKSPACE_NAME}}, {{PROJECT_NAME}}, {{FRONTEND_PORT}}, {{API_PORT}}
4
+
5
+ http:
6
+ routers:
7
+ # Workspace frontend
8
+ {{WORKSPACE_NAME}}-frontend:
9
+ rule: "Host(`{{WORKSPACE_NAME}}.{{PROJECT_NAME}}.localhost`)"
10
+ entryPoints:
11
+ - websecure
12
+ service: {{WORKSPACE_NAME}}-frontend
13
+ tls: {}
14
+
15
+ # Workspace API (if API port is specified)
16
+ {{WORKSPACE_NAME}}-api:
17
+ rule: "Host(`api-{{WORKSPACE_NAME}}.{{PROJECT_NAME}}.localhost`)"
18
+ entryPoints:
19
+ - websecure
20
+ service: {{WORKSPACE_NAME}}-api
21
+ tls: {}
22
+
23
+ services:
24
+ {{WORKSPACE_NAME}}-frontend:
25
+ loadBalancer:
26
+ servers:
27
+ - url: "http://host.docker.internal:{{FRONTEND_PORT}}"
28
+ passHostHeader: true
29
+
30
+ {{WORKSPACE_NAME}}-api:
31
+ loadBalancer:
32
+ servers:
33
+ - url: "http://host.docker.internal:{{API_PORT}}"
34
+ passHostHeader: true
@@ -0,0 +1,45 @@
1
+ # Traefik Static Configuration
2
+ # This file configures Traefik's core behavior
3
+
4
+ # API and Dashboard
5
+ api:
6
+ dashboard: true
7
+ insecure: true # Dashboard accessible without auth on localhost
8
+
9
+ # Entry Points
10
+ entryPoints:
11
+ web:
12
+ address: ":80"
13
+ # Redirect HTTP to HTTPS
14
+ http:
15
+ redirections:
16
+ entryPoint:
17
+ to: websecure
18
+ scheme: https
19
+
20
+ websecure:
21
+ address: ":443"
22
+ http:
23
+ tls: {}
24
+
25
+ # Providers
26
+ providers:
27
+ # File provider for dynamic configuration
28
+ file:
29
+ directory: /etc/traefik/dynamic
30
+ watch: true
31
+
32
+ # Docker provider (for future workspace containers)
33
+ docker:
34
+ endpoint: "unix:///var/run/docker.sock"
35
+ exposedByDefault: false
36
+ network: panopticon
37
+
38
+ # Logging
39
+ log:
40
+ level: INFO
41
+ format: common
42
+
43
+ # Access Logs
44
+ accessLog:
45
+ format: common
@@ -1,352 +0,0 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
- // src/lib/paths.ts
9
- import { homedir } from "os";
10
- import { join } from "path";
11
- var PANOPTICON_HOME = join(homedir(), ".panopticon");
12
- var CONFIG_DIR = PANOPTICON_HOME;
13
- var SKILLS_DIR = join(PANOPTICON_HOME, "skills");
14
- var COMMANDS_DIR = join(PANOPTICON_HOME, "commands");
15
- var AGENTS_DIR = join(PANOPTICON_HOME, "agents");
16
- var BACKUPS_DIR = join(PANOPTICON_HOME, "backups");
17
- var COSTS_DIR = join(PANOPTICON_HOME, "costs");
18
- var CONFIG_FILE = join(CONFIG_DIR, "config.toml");
19
- var CLAUDE_DIR = join(homedir(), ".claude");
20
- var CODEX_DIR = join(homedir(), ".codex");
21
- var CURSOR_DIR = join(homedir(), ".cursor");
22
- var GEMINI_DIR = join(homedir(), ".gemini");
23
- var SYNC_TARGETS = {
24
- claude: {
25
- skills: join(CLAUDE_DIR, "skills"),
26
- commands: join(CLAUDE_DIR, "commands")
27
- },
28
- codex: {
29
- skills: join(CODEX_DIR, "skills"),
30
- commands: join(CODEX_DIR, "commands")
31
- },
32
- cursor: {
33
- skills: join(CURSOR_DIR, "skills"),
34
- commands: join(CURSOR_DIR, "commands")
35
- },
36
- gemini: {
37
- skills: join(GEMINI_DIR, "skills"),
38
- commands: join(GEMINI_DIR, "commands")
39
- }
40
- };
41
- var TEMPLATES_DIR = join(PANOPTICON_HOME, "templates");
42
- var CLAUDE_MD_TEMPLATES = join(TEMPLATES_DIR, "claude-md", "sections");
43
- var INIT_DIRS = [
44
- PANOPTICON_HOME,
45
- SKILLS_DIR,
46
- COMMANDS_DIR,
47
- AGENTS_DIR,
48
- BACKUPS_DIR,
49
- COSTS_DIR,
50
- TEMPLATES_DIR,
51
- CLAUDE_MD_TEMPLATES
52
- ];
53
-
54
- // src/lib/config.ts
55
- import { readFileSync, writeFileSync, existsSync } from "fs";
56
- import { parse, stringify } from "@iarna/toml";
57
- var DEFAULT_CONFIG = {
58
- panopticon: {
59
- version: "1.0.0"
60
- },
61
- sync: {
62
- targets: ["claude"],
63
- backup_before_sync: true
64
- },
65
- trackers: {
66
- primary: "linear"
67
- },
68
- dashboard: {
69
- port: 3001,
70
- api_port: 3002
71
- }
72
- };
73
- function loadConfig() {
74
- if (!existsSync(CONFIG_FILE)) {
75
- return DEFAULT_CONFIG;
76
- }
77
- try {
78
- const content = readFileSync(CONFIG_FILE, "utf8");
79
- const parsed = parse(content);
80
- return { ...DEFAULT_CONFIG, ...parsed };
81
- } catch (error) {
82
- console.error("Warning: Failed to parse config, using defaults");
83
- return DEFAULT_CONFIG;
84
- }
85
- }
86
- function saveConfig(config) {
87
- const content = stringify(config);
88
- writeFileSync(CONFIG_FILE, content, "utf8");
89
- }
90
- function getDefaultConfig() {
91
- return { ...DEFAULT_CONFIG };
92
- }
93
-
94
- // src/lib/shell.ts
95
- import { existsSync as existsSync2, readFileSync as readFileSync2, appendFileSync } from "fs";
96
- import { homedir as homedir2 } from "os";
97
- import { join as join2 } from "path";
98
- function detectShell() {
99
- const shell = process.env.SHELL || "";
100
- if (shell.includes("zsh")) return "zsh";
101
- if (shell.includes("bash")) return "bash";
102
- if (shell.includes("fish")) return "fish";
103
- return "unknown";
104
- }
105
- function getShellRcFile(shell) {
106
- const home = homedir2();
107
- switch (shell) {
108
- case "zsh":
109
- return join2(home, ".zshrc");
110
- case "bash":
111
- const bashrc = join2(home, ".bashrc");
112
- if (existsSync2(bashrc)) return bashrc;
113
- return join2(home, ".bash_profile");
114
- case "fish":
115
- return join2(home, ".config", "fish", "config.fish");
116
- default:
117
- return null;
118
- }
119
- }
120
- var ALIAS_LINE = 'alias pan="panopticon"';
121
- var ALIAS_MARKER = "# Panopticon CLI alias";
122
- function hasAlias(rcFile) {
123
- if (!existsSync2(rcFile)) return false;
124
- const content = readFileSync2(rcFile, "utf8");
125
- return content.includes(ALIAS_MARKER) || content.includes(ALIAS_LINE);
126
- }
127
- function addAlias(rcFile) {
128
- if (hasAlias(rcFile)) return;
129
- const aliasBlock = `
130
- ${ALIAS_MARKER}
131
- ${ALIAS_LINE}
132
- `;
133
- appendFileSync(rcFile, aliasBlock, "utf8");
134
- }
135
- function getAliasInstructions(shell) {
136
- const rcFile = getShellRcFile(shell);
137
- if (!rcFile) {
138
- return `Add this to your shell config:
139
- ${ALIAS_LINE}`;
140
- }
141
- return `Alias added to ${rcFile}. Run:
142
- source ${rcFile}`;
143
- }
144
-
145
- // src/lib/backup.ts
146
- import { existsSync as existsSync3, mkdirSync, readdirSync, cpSync, rmSync } from "fs";
147
- import { join as join3, basename } from "path";
148
- function createBackupTimestamp() {
149
- return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
150
- }
151
- function createBackup(sourceDirs) {
152
- const timestamp = createBackupTimestamp();
153
- const backupPath = join3(BACKUPS_DIR, timestamp);
154
- mkdirSync(backupPath, { recursive: true });
155
- const targets = [];
156
- for (const sourceDir of sourceDirs) {
157
- if (!existsSync3(sourceDir)) continue;
158
- const targetName = basename(sourceDir);
159
- const targetPath = join3(backupPath, targetName);
160
- cpSync(sourceDir, targetPath, { recursive: true });
161
- targets.push(targetName);
162
- }
163
- return {
164
- timestamp,
165
- path: backupPath,
166
- targets
167
- };
168
- }
169
- function listBackups() {
170
- if (!existsSync3(BACKUPS_DIR)) return [];
171
- const entries = readdirSync(BACKUPS_DIR, { withFileTypes: true });
172
- return entries.filter((e) => e.isDirectory()).map((e) => {
173
- const backupPath = join3(BACKUPS_DIR, e.name);
174
- const contents = readdirSync(backupPath);
175
- return {
176
- timestamp: e.name,
177
- path: backupPath,
178
- targets: contents
179
- };
180
- }).sort((a, b) => b.timestamp.localeCompare(a.timestamp));
181
- }
182
- function restoreBackup(timestamp, targetDirs) {
183
- const backupPath = join3(BACKUPS_DIR, timestamp);
184
- if (!existsSync3(backupPath)) {
185
- throw new Error(`Backup not found: ${timestamp}`);
186
- }
187
- const contents = readdirSync(backupPath, { withFileTypes: true });
188
- for (const entry of contents) {
189
- if (!entry.isDirectory()) continue;
190
- const sourcePath = join3(backupPath, entry.name);
191
- const targetPath = targetDirs[entry.name];
192
- if (!targetPath) continue;
193
- if (existsSync3(targetPath)) {
194
- rmSync(targetPath, { recursive: true });
195
- }
196
- cpSync(sourcePath, targetPath, { recursive: true });
197
- }
198
- }
199
- function cleanOldBackups(keepCount = 10) {
200
- const backups = listBackups();
201
- if (backups.length <= keepCount) return 0;
202
- const toRemove = backups.slice(keepCount);
203
- let removed = 0;
204
- for (const backup of toRemove) {
205
- rmSync(backup.path, { recursive: true });
206
- removed++;
207
- }
208
- return removed;
209
- }
210
-
211
- // src/lib/sync.ts
212
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readdirSync as readdirSync2, symlinkSync, unlinkSync, lstatSync, readlinkSync } from "fs";
213
- import { join as join4 } from "path";
214
- function isPanopticonSymlink(targetPath) {
215
- if (!existsSync4(targetPath)) return false;
216
- try {
217
- const stats = lstatSync(targetPath);
218
- if (!stats.isSymbolicLink()) return false;
219
- const linkTarget = readlinkSync(targetPath);
220
- return linkTarget.includes(".panopticon");
221
- } catch {
222
- return false;
223
- }
224
- }
225
- function planSync(runtime) {
226
- const targets = SYNC_TARGETS[runtime];
227
- const plan = {
228
- runtime,
229
- skills: [],
230
- commands: []
231
- };
232
- if (existsSync4(SKILLS_DIR)) {
233
- const skills = readdirSync2(SKILLS_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
234
- for (const skill of skills) {
235
- const sourcePath = join4(SKILLS_DIR, skill.name);
236
- const targetPath = join4(targets.skills, skill.name);
237
- let status = "new";
238
- if (existsSync4(targetPath)) {
239
- if (isPanopticonSymlink(targetPath)) {
240
- status = "symlink";
241
- } else {
242
- status = "conflict";
243
- }
244
- }
245
- plan.skills.push({ name: skill.name, sourcePath, targetPath, status });
246
- }
247
- }
248
- if (existsSync4(COMMANDS_DIR)) {
249
- const commands = readdirSync2(COMMANDS_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
250
- for (const cmd of commands) {
251
- const sourcePath = join4(COMMANDS_DIR, cmd.name);
252
- const targetPath = join4(targets.commands, cmd.name);
253
- let status = "new";
254
- if (existsSync4(targetPath)) {
255
- if (isPanopticonSymlink(targetPath)) {
256
- status = "symlink";
257
- } else {
258
- status = "conflict";
259
- }
260
- }
261
- plan.commands.push({ name: cmd.name, sourcePath, targetPath, status });
262
- }
263
- }
264
- return plan;
265
- }
266
- function executeSync(runtime, options = {}) {
267
- const plan = planSync(runtime);
268
- const result = {
269
- created: [],
270
- skipped: [],
271
- conflicts: []
272
- };
273
- const targets = SYNC_TARGETS[runtime];
274
- mkdirSync2(targets.skills, { recursive: true });
275
- mkdirSync2(targets.commands, { recursive: true });
276
- for (const item of plan.skills) {
277
- if (options.dryRun) {
278
- if (item.status === "new" || item.status === "symlink") {
279
- result.created.push(item.name);
280
- } else {
281
- result.conflicts.push(item.name);
282
- }
283
- continue;
284
- }
285
- if (item.status === "conflict" && !options.force) {
286
- result.conflicts.push(item.name);
287
- continue;
288
- }
289
- if (existsSync4(item.targetPath)) {
290
- unlinkSync(item.targetPath);
291
- }
292
- symlinkSync(item.sourcePath, item.targetPath);
293
- result.created.push(item.name);
294
- }
295
- for (const item of plan.commands) {
296
- if (options.dryRun) {
297
- if (item.status === "new" || item.status === "symlink") {
298
- result.created.push(item.name);
299
- } else {
300
- result.conflicts.push(item.name);
301
- }
302
- continue;
303
- }
304
- if (item.status === "conflict" && !options.force) {
305
- result.conflicts.push(item.name);
306
- continue;
307
- }
308
- if (existsSync4(item.targetPath)) {
309
- unlinkSync(item.targetPath);
310
- }
311
- symlinkSync(item.sourcePath, item.targetPath);
312
- result.created.push(item.name);
313
- }
314
- return result;
315
- }
316
-
317
- export {
318
- __require,
319
- PANOPTICON_HOME,
320
- CONFIG_DIR,
321
- SKILLS_DIR,
322
- COMMANDS_DIR,
323
- AGENTS_DIR,
324
- BACKUPS_DIR,
325
- COSTS_DIR,
326
- CONFIG_FILE,
327
- CLAUDE_DIR,
328
- CODEX_DIR,
329
- CURSOR_DIR,
330
- GEMINI_DIR,
331
- SYNC_TARGETS,
332
- TEMPLATES_DIR,
333
- CLAUDE_MD_TEMPLATES,
334
- INIT_DIRS,
335
- loadConfig,
336
- saveConfig,
337
- getDefaultConfig,
338
- detectShell,
339
- getShellRcFile,
340
- hasAlias,
341
- addAlias,
342
- getAliasInstructions,
343
- createBackupTimestamp,
344
- createBackup,
345
- listBackups,
346
- restoreBackup,
347
- cleanOldBackups,
348
- isPanopticonSymlink,
349
- planSync,
350
- executeSync
351
- };
352
- //# sourceMappingURL=chunk-FR2P66GU.js.map