panopticon-cli 0.4.5 → 0.4.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.
Files changed (68) hide show
  1. package/README.md +84 -2695
  2. package/dist/{agents-B5NRTVHK.js → agents-54LDKMHR.js} +8 -3
  3. package/dist/chunk-44EOY2ZL.js +58 -0
  4. package/dist/chunk-44EOY2ZL.js.map +1 -0
  5. package/dist/chunk-BWGFN44T.js +224 -0
  6. package/dist/chunk-BWGFN44T.js.map +1 -0
  7. package/dist/chunk-F7NQZD6H.js +49 -0
  8. package/dist/chunk-F7NQZD6H.js.map +1 -0
  9. package/dist/chunk-HCTJFIJJ.js +159 -0
  10. package/dist/chunk-HCTJFIJJ.js.map +1 -0
  11. package/dist/chunk-JM6V62LT.js +650 -0
  12. package/dist/chunk-JM6V62LT.js.map +1 -0
  13. package/dist/chunk-K45YD6A3.js +254 -0
  14. package/dist/chunk-K45YD6A3.js.map +1 -0
  15. package/dist/chunk-KGPRXDMX.js +137 -0
  16. package/dist/chunk-KGPRXDMX.js.map +1 -0
  17. package/dist/chunk-KQAEUOML.js +278 -0
  18. package/dist/chunk-KQAEUOML.js.map +1 -0
  19. package/dist/chunk-NYVQC3D7.js +90 -0
  20. package/dist/chunk-NYVQC3D7.js.map +1 -0
  21. package/dist/chunk-PUR532O7.js +1556 -0
  22. package/dist/chunk-PUR532O7.js.map +1 -0
  23. package/dist/chunk-VTDDVLCK.js +1977 -0
  24. package/dist/chunk-VTDDVLCK.js.map +1 -0
  25. package/dist/chunk-Z24TY3XN.js +916 -0
  26. package/dist/chunk-Z24TY3XN.js.map +1 -0
  27. package/dist/chunk-ZHC57RCV.js +44 -0
  28. package/dist/chunk-ZHC57RCV.js.map +1 -0
  29. package/dist/{chunk-ITI4IC5A.js → chunk-ZZ3477GY.js} +69 -100
  30. package/dist/chunk-ZZ3477GY.js.map +1 -0
  31. package/dist/cli/index.js +4664 -2912
  32. package/dist/cli/index.js.map +1 -1
  33. package/dist/dashboard/public/assets/index-CRqsEkmn.css +32 -0
  34. package/dist/dashboard/public/assets/index-DPSUbu4A.js +645 -0
  35. package/dist/dashboard/public/index.html +15 -3
  36. package/dist/dashboard/server.js +45663 -17860
  37. package/dist/dns-L3L2BB27.js +30 -0
  38. package/dist/dns-L3L2BB27.js.map +1 -0
  39. package/dist/index.d.ts +63 -3
  40. package/dist/index.js +42 -18
  41. package/dist/index.js.map +1 -1
  42. package/dist/projects-ESIB34QQ.js +43 -0
  43. package/dist/projects-ESIB34QQ.js.map +1 -0
  44. package/dist/remote-agents-Z3R2A5BN.js +25 -0
  45. package/dist/remote-agents-Z3R2A5BN.js.map +1 -0
  46. package/dist/remote-workspace-HI4VML6H.js +179 -0
  47. package/dist/remote-workspace-HI4VML6H.js.map +1 -0
  48. package/dist/specialist-context-SNCJ7O7G.js +256 -0
  49. package/dist/specialist-context-SNCJ7O7G.js.map +1 -0
  50. package/dist/specialist-logs-A7ODEK2T.js +43 -0
  51. package/dist/specialist-logs-A7ODEK2T.js.map +1 -0
  52. package/dist/specialists-C7XLNSXQ.js +121 -0
  53. package/dist/specialists-C7XLNSXQ.js.map +1 -0
  54. package/dist/traefik-WI3KSRGG.js +12 -0
  55. package/dist/traefik-WI3KSRGG.js.map +1 -0
  56. package/package.json +1 -1
  57. package/templates/traefik/docker-compose.yml +1 -1
  58. package/templates/traefik/dynamic/panopticon.yml.template +41 -0
  59. package/templates/traefik/traefik.yml +8 -0
  60. package/dist/chunk-7HHDVXBM.js +0 -349
  61. package/dist/chunk-7HHDVXBM.js.map +0 -1
  62. package/dist/chunk-H45CLB7E.js +0 -2044
  63. package/dist/chunk-H45CLB7E.js.map +0 -1
  64. package/dist/chunk-ITI4IC5A.js.map +0 -1
  65. package/dist/dashboard/public/assets/index-BDd8hGYb.css +0 -32
  66. package/dist/dashboard/public/assets/index-sFwLPko-.js +0 -556
  67. package/templates/traefik/dynamic/panopticon.yml +0 -51
  68. /package/dist/{agents-B5NRTVHK.js.map → agents-54LDKMHR.js.map} +0 -0
@@ -0,0 +1,30 @@
1
+ import {
2
+ addDnsEntry,
3
+ addDnsmasqEntry,
4
+ addHostsFileEntry,
5
+ addWsl2HostEntry,
6
+ detectDnsSyncMethod,
7
+ ensureBaseDomain,
8
+ removeDnsEntry,
9
+ removeDnsmasqEntry,
10
+ removeHostsFileEntry,
11
+ removeWsl2HostEntry,
12
+ restartDnsmasq,
13
+ syncDnsToWindows
14
+ } from "./chunk-BWGFN44T.js";
15
+ import "./chunk-ZHC57RCV.js";
16
+ export {
17
+ addDnsEntry,
18
+ addDnsmasqEntry,
19
+ addHostsFileEntry,
20
+ addWsl2HostEntry,
21
+ detectDnsSyncMethod,
22
+ ensureBaseDomain,
23
+ removeDnsEntry,
24
+ removeDnsmasqEntry,
25
+ removeHostsFileEntry,
26
+ removeWsl2HostEntry,
27
+ restartDnsmasq,
28
+ syncDnsToWindows
29
+ };
30
+ //# sourceMappingURL=dns-L3L2BB27.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/index.d.ts CHANGED
@@ -17,6 +17,7 @@ declare const CLAUDE_DIR: string;
17
17
  declare const CODEX_DIR: string;
18
18
  declare const CURSOR_DIR: string;
19
19
  declare const GEMINI_DIR: string;
20
+ declare const OPENCODE_DIR: string;
20
21
  declare const SYNC_TARGETS: {
21
22
  readonly claude: {
22
23
  readonly skills: string;
@@ -38,6 +39,11 @@ declare const SYNC_TARGETS: {
38
39
  readonly commands: string;
39
40
  readonly agents: string;
40
41
  };
42
+ readonly opencode: {
43
+ readonly skills: string;
44
+ readonly commands: string;
45
+ readonly agents: string;
46
+ };
41
47
  };
42
48
  type Runtime = keyof typeof SYNC_TARGETS;
43
49
  declare const TEMPLATES_DIR: string;
@@ -229,6 +235,39 @@ interface TrackersConfig {
229
235
  gitlab?: GitLabConfig;
230
236
  rally?: RallyConfig;
231
237
  }
238
+ interface RemoteExeConfig {
239
+ /** Shared infrastructure VM for postgres/redis/traefik */
240
+ infra_vm?: string;
241
+ /** Postgres settings on infra VM */
242
+ postgres_host?: string;
243
+ postgres_port?: number;
244
+ postgres_user?: string;
245
+ postgres_password_env?: string;
246
+ /** Redis settings on infra VM */
247
+ redis_host?: string;
248
+ redis_port?: number;
249
+ }
250
+ interface RemoteConfig {
251
+ /** Enable remote workspace support */
252
+ enabled: boolean;
253
+ /** Remote provider type */
254
+ provider?: 'exe';
255
+ /** Default location for new workspaces */
256
+ default_location?: 'local' | 'remote';
257
+ /** Auto-hibernate idle workspaces after N minutes (0 = disabled) */
258
+ auto_hibernate_minutes?: number;
259
+ /** exe.dev specific configuration */
260
+ exe?: RemoteExeConfig;
261
+ }
262
+ interface ShadowConfig {
263
+ enabled: boolean;
264
+ trackers: {
265
+ linear: boolean;
266
+ github: boolean;
267
+ gitlab: boolean;
268
+ rally: boolean;
269
+ };
270
+ }
232
271
  interface PanopticonConfig {
233
272
  panopticon: {
234
273
  version: string;
@@ -244,11 +283,14 @@ interface PanopticonConfig {
244
283
  port: number;
245
284
  api_port: number;
246
285
  };
247
- traefik?: {
286
+ traefik: {
248
287
  enabled: boolean;
249
288
  dashboard_port?: number;
250
289
  domain?: string;
290
+ dns_sync_method?: 'wsl2hosts' | 'hosts_file' | 'dnsmasq';
251
291
  };
292
+ remote?: RemoteConfig;
293
+ shadow: ShadowConfig;
252
294
  }
253
295
  declare function loadConfig(): PanopticonConfig;
254
296
  declare function saveConfig(config: PanopticonConfig): void;
@@ -519,7 +561,7 @@ declare class LinkManager {
519
561
  }
520
562
  declare function getLinkManager(): LinkManager;
521
563
 
522
- type AnthropicModel = 'claude-opus-4-5' | 'claude-sonnet-4-5' | 'claude-haiku-4-5';
564
+ type AnthropicModel = 'claude-opus-4-6' | 'claude-sonnet-4-5' | 'claude-haiku-4-5';
523
565
  type OpenAIModel = 'gpt-5.2-codex' | 'o3-deep-research' | 'gpt-4o' | 'gpt-4o-mini';
524
566
  type GoogleModel = 'gemini-3-pro-preview' | 'gemini-3-flash-preview' | 'gemini-2.5-pro' | 'gemini-2.5-flash';
525
567
  type ZAIModel = 'glm-4.7' | 'glm-4.7-flash';
@@ -580,6 +622,24 @@ declare function getAvailableModels(settings: SettingsConfig): {
580
622
  zai: ZAIModel[];
581
623
  kimi: KimiModel[];
582
624
  };
625
+ /**
626
+ * Check if a model ID is an Anthropic model
627
+ * Anthropic models can be run directly with `claude` CLI
628
+ */
629
+ declare function isAnthropicModel(modelId: ModelId | string): boolean;
630
+ /**
631
+ * Get the Claude CLI model flag for an Anthropic model
632
+ * Maps our model IDs to Claude's expected format
633
+ */
634
+ declare function getClaudeModelFlag(modelId: ModelId | string): string;
635
+ /**
636
+ * Get the command to run an agent with a specific model
637
+ * Returns 'claude' for Anthropic models, 'claude-code-router' for others
638
+ */
639
+ declare function getAgentCommand(modelId: ModelId | string): {
640
+ command: string;
641
+ args: string[];
642
+ };
583
643
 
584
644
  /**
585
645
  * Provider Configuration and Compatibility
@@ -642,4 +702,4 @@ declare function needsRouter(apiKeys: {
642
702
  */
643
703
  declare function getProviderEnv(provider: ProviderConfig, apiKey: string): Record<string, string>;
644
704
 
645
- export { AGENTS_DIR, type AnthropicModel, type ApiKeysConfig, BACKUPS_DIR, BIN_DIR, type BackupInfo, CERTS_DIR, CLAUDE_DIR, CLAUDE_MD_TEMPLATES, CODEX_DIR, COMMANDS_DIR, CONFIG_DIR, CONFIG_FILE, COSTS_DIR, CURSOR_DIR, type Comment, type ComplexityLevel, type ComplexityModels, GEMINI_DIR, type GitHubConfig, GitHubTracker, type GitLabConfig, GitLabTracker, type GoogleModel, HEARTBEATS_DIR, type HookItem, INIT_DIRS, type Issue, type IssueFilters, IssueNotFoundError, type IssueState, type IssueTracker, type IssueUpdate, type KimiModel, type LinearConfig, LinearTracker, type LinkDirection, LinkManager, type ModelId, type ModelsConfig, type NewIssue, NotImplementedError, type OpenAIModel, PANOPTICON_HOME, PROVIDERS, type PanopticonConfig, type ProviderCompatibility, type ProviderConfig, type ProviderName, type RallyConfig, type Runtime, SETTINGS_FILE, SKILLS_DIR, SOURCE_DEV_SKILLS_DIR, SOURCE_SCRIPTS_DIR, SOURCE_SKILLS_DIR, SOURCE_TEMPLATES_DIR, SOURCE_TRAEFIK_TEMPLATES, SYNC_TARGETS, type SettingsConfig, type Shell, type SpecialistModels, 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, type ZAIModel, addAlias, cleanOldBackups, createBackup, createBackupTimestamp, createTracker, createTrackerFromConfig, detectShell, executeSync, formatIssueRef, getAliasInstructions, getAllTrackers, getAvailableModels, getDefaultConfig, getDefaultSettings, getDirectProviders, getLinkManager, getPrimaryTracker, getProviderEnv, getProviderForModel, getRouterProviders, getSecondaryTracker, getShellRcFile, hasAlias, isDevMode, isPanopticonSymlink, listBackups, loadConfig, loadSettings, needsRouter, parseIssueRef, planHooksSync, planSync, requiresRouter, restoreBackup, saveConfig, saveSettings, syncHooks, validateSettings };
705
+ export { AGENTS_DIR, type AnthropicModel, type ApiKeysConfig, BACKUPS_DIR, BIN_DIR, type BackupInfo, CERTS_DIR, CLAUDE_DIR, CLAUDE_MD_TEMPLATES, CODEX_DIR, COMMANDS_DIR, CONFIG_DIR, CONFIG_FILE, COSTS_DIR, CURSOR_DIR, type Comment, type ComplexityLevel, type ComplexityModels, GEMINI_DIR, type GitHubConfig, GitHubTracker, type GitLabConfig, GitLabTracker, type GoogleModel, HEARTBEATS_DIR, type HookItem, INIT_DIRS, type Issue, type IssueFilters, IssueNotFoundError, type IssueState, type IssueTracker, type IssueUpdate, type KimiModel, type LinearConfig, LinearTracker, type LinkDirection, LinkManager, type ModelId, type ModelsConfig, type NewIssue, NotImplementedError, OPENCODE_DIR, type OpenAIModel, PANOPTICON_HOME, PROVIDERS, type PanopticonConfig, type ProviderCompatibility, type ProviderConfig, type ProviderName, type RallyConfig, type RemoteConfig, type RemoteExeConfig, type Runtime, SETTINGS_FILE, SKILLS_DIR, SOURCE_DEV_SKILLS_DIR, SOURCE_SCRIPTS_DIR, SOURCE_SKILLS_DIR, SOURCE_TEMPLATES_DIR, SOURCE_TRAEFIK_TEMPLATES, SYNC_TARGETS, type SettingsConfig, type ShadowConfig, type Shell, type SpecialistModels, 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, type ZAIModel, addAlias, cleanOldBackups, createBackup, createBackupTimestamp, createTracker, createTrackerFromConfig, detectShell, executeSync, formatIssueRef, getAgentCommand, getAliasInstructions, getAllTrackers, getAvailableModels, getClaudeModelFlag, getDefaultConfig, getDefaultSettings, getDirectProviders, getLinkManager, getPrimaryTracker, getProviderEnv, getProviderForModel, getRouterProviders, getSecondaryTracker, getShellRcFile, hasAlias, isAnthropicModel, isDevMode, isPanopticonSymlink, listBackups, loadConfig, loadSettings, needsRouter, parseIssueRef, planHooksSync, planSync, requiresRouter, restoreBackup, saveConfig, saveSettings, syncHooks, validateSettings };
package/dist/index.js CHANGED
@@ -17,7 +17,6 @@ import {
17
17
  formatIssueRef,
18
18
  getAliasInstructions,
19
19
  getAllTrackers,
20
- getDefaultConfig,
21
20
  getLinkManager,
22
21
  getPrimaryTracker,
23
22
  getSecondaryTracker,
@@ -25,14 +24,36 @@ import {
25
24
  hasAlias,
26
25
  isPanopticonSymlink,
27
26
  listBackups,
28
- loadConfig,
29
27
  parseIssueRef,
30
28
  planHooksSync,
31
29
  planSync,
32
30
  restoreBackup,
33
- saveConfig,
34
31
  syncHooks
35
- } from "./chunk-ITI4IC5A.js";
32
+ } from "./chunk-ZZ3477GY.js";
33
+ import {
34
+ PROVIDERS,
35
+ getAgentCommand,
36
+ getAvailableModels,
37
+ getClaudeModelFlag,
38
+ getDefaultSettings,
39
+ getDirectProviders,
40
+ getProviderEnv,
41
+ getProviderForModel,
42
+ getRouterProviders,
43
+ init_providers,
44
+ init_settings,
45
+ isAnthropicModel,
46
+ loadSettings,
47
+ needsRouter,
48
+ requiresRouter,
49
+ saveSettings,
50
+ validateSettings
51
+ } from "./chunk-KQAEUOML.js";
52
+ import {
53
+ getDefaultConfig,
54
+ loadConfig,
55
+ saveConfig
56
+ } from "./chunk-NYVQC3D7.js";
36
57
  import {
37
58
  AGENTS_DIR,
38
59
  BACKUPS_DIR,
@@ -49,8 +70,8 @@ import {
49
70
  GEMINI_DIR,
50
71
  HEARTBEATS_DIR,
51
72
  INIT_DIRS,
73
+ OPENCODE_DIR,
52
74
  PANOPTICON_HOME,
53
- PROVIDERS,
54
75
  SETTINGS_FILE,
55
76
  SKILLS_DIR,
56
77
  SOURCE_DEV_SKILLS_DIR,
@@ -63,19 +84,18 @@ import {
63
84
  TRAEFIK_CERTS_DIR,
64
85
  TRAEFIK_DIR,
65
86
  TRAEFIK_DYNAMIC_DIR,
66
- getAvailableModels,
67
- getDefaultSettings,
68
- getDirectProviders,
69
- getProviderEnv,
70
- getProviderForModel,
71
- getRouterProviders,
72
- isDevMode,
73
- loadSettings,
74
- needsRouter,
75
- requiresRouter,
76
- saveSettings,
77
- validateSettings
78
- } from "./chunk-7HHDVXBM.js";
87
+ init_paths,
88
+ isDevMode
89
+ } from "./chunk-KGPRXDMX.js";
90
+ import {
91
+ init_esm_shims
92
+ } from "./chunk-ZHC57RCV.js";
93
+
94
+ // src/index.ts
95
+ init_esm_shims();
96
+ init_paths();
97
+ init_providers();
98
+ init_settings();
79
99
  export {
80
100
  AGENTS_DIR,
81
101
  BACKUPS_DIR,
@@ -98,6 +118,7 @@ export {
98
118
  LinearTracker,
99
119
  LinkManager,
100
120
  NotImplementedError,
121
+ OPENCODE_DIR,
101
122
  PANOPTICON_HOME,
102
123
  PROVIDERS,
103
124
  SETTINGS_FILE,
@@ -122,9 +143,11 @@ export {
122
143
  detectShell,
123
144
  executeSync,
124
145
  formatIssueRef,
146
+ getAgentCommand,
125
147
  getAliasInstructions,
126
148
  getAllTrackers,
127
149
  getAvailableModels,
150
+ getClaudeModelFlag,
128
151
  getDefaultConfig,
129
152
  getDefaultSettings,
130
153
  getDirectProviders,
@@ -136,6 +159,7 @@ export {
136
159
  getSecondaryTracker,
137
160
  getShellRcFile,
138
161
  hasAlias,
162
+ isAnthropicModel,
139
163
  isDevMode,
140
164
  isPanopticonSymlink,
141
165
  listBackups,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Panopticon CLI - Main exports for library usage\nexport * from './lib/paths.js';\nexport * from './lib/config.js';\nexport * from './lib/shell.js';\nexport * from './lib/backup.js';\nexport * from './lib/sync.js';\nexport * from './lib/tracker/index.js';\nexport * from './lib/providers.js';\nexport * from './lib/settings.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AAMA;AACA;","names":[]}
@@ -0,0 +1,43 @@
1
+ import {
2
+ PROJECTS_CONFIG_FILE,
3
+ createDefaultProjectsConfig,
4
+ extractTeamPrefix,
5
+ findProjectByTeam,
6
+ getProject,
7
+ getSpecialistConfig,
8
+ getSpecialistPromptOverride,
9
+ getSpecialistRetention,
10
+ hasProjects,
11
+ init_projects,
12
+ initializeProjectsConfig,
13
+ listProjects,
14
+ loadProjectsConfig,
15
+ registerProject,
16
+ resolveProjectFromIssue,
17
+ resolveProjectPath,
18
+ saveProjectsConfig,
19
+ unregisterProject
20
+ } from "./chunk-K45YD6A3.js";
21
+ import "./chunk-KGPRXDMX.js";
22
+ import "./chunk-ZHC57RCV.js";
23
+ init_projects();
24
+ export {
25
+ PROJECTS_CONFIG_FILE,
26
+ createDefaultProjectsConfig,
27
+ extractTeamPrefix,
28
+ findProjectByTeam,
29
+ getProject,
30
+ getSpecialistConfig,
31
+ getSpecialistPromptOverride,
32
+ getSpecialistRetention,
33
+ hasProjects,
34
+ initializeProjectsConfig,
35
+ listProjects,
36
+ loadProjectsConfig,
37
+ registerProject,
38
+ resolveProjectFromIssue,
39
+ resolveProjectPath,
40
+ saveProjectsConfig,
41
+ unregisterProject
42
+ };
43
+ //# sourceMappingURL=projects-ESIB34QQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,25 @@
1
+ import {
2
+ getRemoteAgentOutput,
3
+ init_remote_agents,
4
+ isRemoteAgentRunning,
5
+ killRemoteAgent,
6
+ listRemoteAgents,
7
+ loadRemoteAgentState,
8
+ pollRemoteAgentStatus,
9
+ sendToRemoteAgent,
10
+ spawnRemoteAgent
11
+ } from "./chunk-HCTJFIJJ.js";
12
+ import "./chunk-JM6V62LT.js";
13
+ import "./chunk-ZHC57RCV.js";
14
+ init_remote_agents();
15
+ export {
16
+ getRemoteAgentOutput,
17
+ isRemoteAgentRunning,
18
+ killRemoteAgent,
19
+ listRemoteAgents,
20
+ loadRemoteAgentState,
21
+ pollRemoteAgentStatus,
22
+ sendToRemoteAgent,
23
+ spawnRemoteAgent
24
+ };
25
+ //# sourceMappingURL=remote-agents-Z3R2A5BN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,179 @@
1
+ import {
2
+ saveWorkspaceMetadata
3
+ } from "./chunk-44EOY2ZL.js";
4
+ import {
5
+ extractTeamPrefix,
6
+ findProjectByTeam,
7
+ init_projects
8
+ } from "./chunk-K45YD6A3.js";
9
+ import {
10
+ createExeProvider,
11
+ init_exe_provider
12
+ } from "./chunk-JM6V62LT.js";
13
+ import {
14
+ loadConfig
15
+ } from "./chunk-NYVQC3D7.js";
16
+ import "./chunk-KGPRXDMX.js";
17
+ import {
18
+ init_esm_shims
19
+ } from "./chunk-ZHC57RCV.js";
20
+
21
+ // src/lib/remote-workspace.ts
22
+ init_esm_shims();
23
+ import chalk from "chalk";
24
+ import { exec } from "child_process";
25
+ import { promisify } from "util";
26
+ init_exe_provider();
27
+ init_projects();
28
+ var execAsync = promisify(exec);
29
+ async function createRemoteWorkspace(issueId, options = {}) {
30
+ const config = loadConfig();
31
+ const remoteConfig = config.remote;
32
+ if (!remoteConfig?.enabled) {
33
+ throw new Error("Remote workspaces not enabled. Run `pan remote setup`");
34
+ }
35
+ const normalizedId = issueId.toLowerCase().replace(/[^a-z0-9-]/g, "-");
36
+ const branchName = `feature/${normalizedId}`;
37
+ const infraVm = remoteConfig.exe?.infra_vm || "pan-infra";
38
+ const exe = createExeProvider({ infraVm });
39
+ const teamPrefix = extractTeamPrefix(issueId);
40
+ const projectConfig = teamPrefix ? findProjectByTeam(teamPrefix) : null;
41
+ const projectRoot = projectConfig?.path || process.cwd();
42
+ let projectId = teamPrefix?.toLowerCase();
43
+ if (!projectId && projectConfig?.linear_team) {
44
+ projectId = projectConfig.linear_team.toLowerCase();
45
+ }
46
+ if (!projectId) {
47
+ try {
48
+ const { stdout } = await execAsync("git remote get-url origin", {
49
+ cwd: projectRoot,
50
+ encoding: "utf-8"
51
+ });
52
+ const repoMatch = stdout.trim().match(/\/([^\/]+?)(\.git)?$/);
53
+ projectId = repoMatch ? repoMatch[1].toLowerCase().replace(/[^a-z0-9-]/g, "-") : "proj";
54
+ } catch {
55
+ projectId = "proj";
56
+ }
57
+ }
58
+ const vmName = `${projectId}-${normalizedId}-ws`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
59
+ if (options.dryRun) {
60
+ console.log(chalk.bold("Would create remote workspace:"));
61
+ console.log(` VM: ${chalk.cyan(vmName)}`);
62
+ console.log(` Project: ${chalk.dim(projectId)}`);
63
+ console.log(` Infra: ${chalk.dim(infraVm)}`);
64
+ console.log(` Branch: ${chalk.dim(branchName)}`);
65
+ throw new Error("Dry run - not implemented in this module");
66
+ }
67
+ let repoUrl = "";
68
+ try {
69
+ const { stdout } = await execAsync("git remote get-url origin", {
70
+ cwd: projectRoot,
71
+ encoding: "utf-8"
72
+ });
73
+ repoUrl = stdout.trim();
74
+ } catch {
75
+ throw new Error("Could not determine git remote URL. Make sure you are in a git repository with a remote origin.");
76
+ }
77
+ if (options.spinner) {
78
+ options.spinner.text = "Creating VM (this may take 1-2 minutes)...";
79
+ }
80
+ await exe.createVm(vmName);
81
+ if (options.spinner) {
82
+ options.spinner.text = "Cloning repository on VM...";
83
+ }
84
+ await exe.ssh(vmName, "mkdir -p ~/.ssh && ssh-keyscan -t ed25519,rsa github.com >> ~/.ssh/known_hosts 2>/dev/null");
85
+ const cloneResult = await exe.ssh(vmName, `git clone ${repoUrl} ~/workspace`);
86
+ if (cloneResult.exitCode !== 0) {
87
+ await exe.deleteVm(vmName);
88
+ throw new Error(`Failed to clone: ${cloneResult.stderr}`);
89
+ }
90
+ if (options.spinner) {
91
+ options.spinner.text = "Creating feature branch...";
92
+ }
93
+ const branchResult = await exe.ssh(vmName, `cd ~/workspace && git checkout -b ${branchName}`);
94
+ if (branchResult.exitCode !== 0) {
95
+ await exe.ssh(vmName, `cd ~/workspace && git checkout ${branchName} || git checkout -b ${branchName}`);
96
+ }
97
+ const envContent = `
98
+ # Panopticon Remote Workspace
99
+ WORKSPACE_ID=${normalizedId}
100
+ ISSUE_ID=${issueId.toUpperCase()}
101
+
102
+ # Shared Infrastructure
103
+ POSTGRES_HOST=${infraVm}
104
+ POSTGRES_PORT=5432
105
+ POSTGRES_USER=postgres
106
+ POSTGRES_PASSWORD=\${PAN_POSTGRES_PASSWORD:-panopticon}
107
+ DATABASE_NAME=myn_${normalizedId.replace(/-/g, "_")}
108
+
109
+ REDIS_HOST=${infraVm}
110
+ REDIS_PORT=6379
111
+ REDIS_DATABASE=0
112
+
113
+ # Spring Boot (if applicable)
114
+ SPRING_DATASOURCE_URL=jdbc:postgresql://${infraVm}:5432/myn_${normalizedId.replace(/-/g, "_")}
115
+ SPRING_DATA_REDIS_HOST=${infraVm}
116
+ `;
117
+ await exe.ssh(vmName, `cat > ~/workspace/.env.remote << 'EOF'
118
+ ${envContent}
119
+ EOF`);
120
+ const dbName = `myn_${normalizedId.replace(/-/g, "_")}`;
121
+ try {
122
+ await exe.ssh(infraVm, `docker exec pan-postgres psql -U postgres -c "CREATE DATABASE ${dbName}" 2>/dev/null || true`);
123
+ } catch {
124
+ }
125
+ if (options.spinner) {
126
+ options.spinner.text = "Installing beads CLI...";
127
+ }
128
+ const bdInstalled = await exe.installBeads(vmName);
129
+ if (bdInstalled) {
130
+ await exe.initBeads(vmName, "~/workspace");
131
+ }
132
+ if (options.spinner) {
133
+ options.spinner.text = "Copying skills to remote VM...";
134
+ }
135
+ await exe.copySkillsToVm(vmName);
136
+ let containersStarted = false;
137
+ let frontendUrl = "";
138
+ let apiUrl = "";
139
+ const composeCheck = await exe.ssh(vmName, "ls ~/workspace/docker-compose.yml ~/workspace/.devcontainer/docker-compose.yml 2>/dev/null | head -1");
140
+ if (composeCheck.stdout.trim()) {
141
+ if (options.spinner) {
142
+ options.spinner.text = "Starting containers...";
143
+ }
144
+ const composeDir = composeCheck.stdout.includes(".devcontainer") ? "~/workspace/.devcontainer" : "~/workspace";
145
+ const upResult = await exe.ssh(vmName, `cd ${composeDir} && docker compose up -d 2>&1`);
146
+ containersStarted = upResult.exitCode === 0;
147
+ if (containersStarted) {
148
+ if (options.spinner) {
149
+ options.spinner.text = "Exposing ports...";
150
+ }
151
+ try {
152
+ frontendUrl = await exe.exposePort(vmName, 4173);
153
+ apiUrl = await exe.exposePort(vmName, 7e3);
154
+ } catch {
155
+ }
156
+ }
157
+ }
158
+ const metadata = {
159
+ id: normalizedId,
160
+ issue: issueId.toUpperCase(),
161
+ provider: "exe",
162
+ vmName,
163
+ infraVm,
164
+ database: dbName,
165
+ redisDb: 0,
166
+ urls: {
167
+ frontend: frontendUrl || void 0,
168
+ api: apiUrl || void 0
169
+ },
170
+ created: /* @__PURE__ */ new Date(),
171
+ location: "remote"
172
+ };
173
+ saveWorkspaceMetadata(metadata);
174
+ return metadata;
175
+ }
176
+ export {
177
+ createRemoteWorkspace
178
+ };
179
+ //# sourceMappingURL=remote-workspace-HI4VML6H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/remote-workspace.ts"],"sourcesContent":["/**\n * Remote Workspace Creation\n *\n * Shared module for creating remote workspaces.\n * Used by both workspace.ts (explicit creation) and work/issue.ts (auto-creation).\n */\n\nimport chalk from 'chalk';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { loadConfig } from './config.js';\nimport { createExeProvider } from './remote/exe-provider.js';\nimport { saveWorkspaceMetadata } from './remote/workspace-metadata.js';\nimport type { RemoteWorkspaceMetadata } from './remote/interface.js';\nimport { extractTeamPrefix, findProjectByTeam, resolveProjectFromIssue } from './projects.js';\n\nconst execAsync = promisify(exec);\n\nexport interface CreateRemoteWorkspaceOptions {\n dryRun?: boolean;\n spinner?: { text: string };\n}\n\n/**\n * Create a remote workspace on exe.dev\n */\nexport async function createRemoteWorkspace(\n issueId: string,\n options: CreateRemoteWorkspaceOptions = {}\n): Promise<RemoteWorkspaceMetadata> {\n const config = loadConfig();\n const remoteConfig = config.remote;\n\n if (!remoteConfig?.enabled) {\n throw new Error('Remote workspaces not enabled. Run `pan remote setup`');\n }\n\n const normalizedId = issueId.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n const branchName = `feature/${normalizedId}`;\n const infraVm = remoteConfig.exe?.infra_vm || 'pan-infra';\n const exe = createExeProvider({ infraVm });\n\n // Determine project context\n const teamPrefix = extractTeamPrefix(issueId);\n const projectConfig = teamPrefix ? findProjectByTeam(teamPrefix) : null;\n const projectRoot = projectConfig?.path || process.cwd();\n\n // Determine project identifier for VM name\n let projectId = teamPrefix?.toLowerCase();\n if (!projectId && projectConfig?.linear_team) {\n projectId = projectConfig.linear_team.toLowerCase();\n }\n if (!projectId) {\n try {\n const { stdout } = await execAsync('git remote get-url origin', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n const repoMatch = stdout.trim().match(/\\/([^\\/]+?)(\\.git)?$/);\n projectId = repoMatch ? repoMatch[1].toLowerCase().replace(/[^a-z0-9-]/g, '-') : 'proj';\n } catch {\n projectId = 'proj';\n }\n }\n\n // VM names must be valid hostnames (start with letter, alphanumeric + hyphens)\n const vmName = `${projectId}-${normalizedId}-ws`.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n\n if (options.dryRun) {\n console.log(chalk.bold('Would create remote workspace:'));\n console.log(` VM: ${chalk.cyan(vmName)}`);\n console.log(` Project: ${chalk.dim(projectId)}`);\n console.log(` Infra: ${chalk.dim(infraVm)}`);\n console.log(` Branch: ${chalk.dim(branchName)}`);\n throw new Error('Dry run - not implemented in this module');\n }\n\n // Get git remote URL\n let repoUrl = '';\n try {\n const { stdout } = await execAsync('git remote get-url origin', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n repoUrl = stdout.trim();\n } catch {\n throw new Error('Could not determine git remote URL. Make sure you are in a git repository with a remote origin.');\n }\n\n if (options.spinner) {\n options.spinner.text = 'Creating VM (this may take 1-2 minutes)...';\n }\n\n // Step 1: Create VM\n await exe.createVm(vmName);\n\n // Step 2: Add GitHub host key and clone repository on VM\n if (options.spinner) {\n options.spinner.text = 'Cloning repository on VM...';\n }\n await exe.ssh(vmName, 'mkdir -p ~/.ssh && ssh-keyscan -t ed25519,rsa github.com >> ~/.ssh/known_hosts 2>/dev/null');\n const cloneResult = await exe.ssh(vmName, `git clone ${repoUrl} ~/workspace`);\n if (cloneResult.exitCode !== 0) {\n await exe.deleteVm(vmName);\n throw new Error(`Failed to clone: ${cloneResult.stderr}`);\n }\n\n // Step 3: Create feature branch\n if (options.spinner) {\n options.spinner.text = 'Creating feature branch...';\n }\n const branchResult = await exe.ssh(vmName, `cd ~/workspace && git checkout -b ${branchName}`);\n if (branchResult.exitCode !== 0) {\n await exe.ssh(vmName, `cd ~/workspace && git checkout ${branchName} || git checkout -b ${branchName}`);\n }\n\n // Step 4: Configure environment for shared infra\n const envContent = `\n# Panopticon Remote Workspace\nWORKSPACE_ID=${normalizedId}\nISSUE_ID=${issueId.toUpperCase()}\n\n# Shared Infrastructure\nPOSTGRES_HOST=${infraVm}\nPOSTGRES_PORT=5432\nPOSTGRES_USER=postgres\nPOSTGRES_PASSWORD=\\${PAN_POSTGRES_PASSWORD:-panopticon}\nDATABASE_NAME=myn_${normalizedId.replace(/-/g, '_')}\n\nREDIS_HOST=${infraVm}\nREDIS_PORT=6379\nREDIS_DATABASE=0\n\n# Spring Boot (if applicable)\nSPRING_DATASOURCE_URL=jdbc:postgresql://${infraVm}:5432/myn_${normalizedId.replace(/-/g, '_')}\nSPRING_DATA_REDIS_HOST=${infraVm}\n`;\n\n await exe.ssh(vmName, `cat > ~/workspace/.env.remote << 'EOF'\n${envContent}\nEOF`);\n\n // Step 5: Create database on shared postgres\n const dbName = `myn_${normalizedId.replace(/-/g, '_')}`;\n try {\n await exe.ssh(infraVm, `docker exec pan-postgres psql -U postgres -c \"CREATE DATABASE ${dbName}\" 2>/dev/null || true`);\n } catch {\n // Non-fatal - database might already exist\n }\n\n // Step 6: Install beads CLI globally on remote VM\n if (options.spinner) {\n options.spinner.text = 'Installing beads CLI...';\n }\n const bdInstalled = await exe.installBeads(vmName);\n if (bdInstalled) {\n await exe.initBeads(vmName, '~/workspace');\n }\n\n // Step 6.5: Copy essential skills to remote VM\n if (options.spinner) {\n options.spinner.text = 'Copying skills to remote VM...';\n }\n await exe.copySkillsToVm(vmName);\n\n // Step 7: Start containers if docker compose exists\n let containersStarted = false;\n let frontendUrl = '';\n let apiUrl = '';\n\n const composeCheck = await exe.ssh(vmName, 'ls ~/workspace/docker-compose.yml ~/workspace/.devcontainer/docker-compose.yml 2>/dev/null | head -1');\n\n if (composeCheck.stdout.trim()) {\n if (options.spinner) {\n options.spinner.text = 'Starting containers...';\n }\n const composeDir = composeCheck.stdout.includes('.devcontainer')\n ? '~/workspace/.devcontainer'\n : '~/workspace';\n\n const upResult = await exe.ssh(vmName, `cd ${composeDir} && docker compose up -d 2>&1`);\n containersStarted = upResult.exitCode === 0;\n\n if (containersStarted) {\n if (options.spinner) {\n options.spinner.text = 'Exposing ports...';\n }\n try {\n frontendUrl = await exe.exposePort(vmName, 4173);\n apiUrl = await exe.exposePort(vmName, 7000);\n } catch {\n // Port exposure failed - not critical\n }\n }\n }\n\n // Step 8: Save workspace metadata\n const metadata: RemoteWorkspaceMetadata = {\n id: normalizedId,\n issue: issueId.toUpperCase(),\n provider: 'exe',\n vmName,\n infraVm,\n database: dbName,\n redisDb: 0,\n urls: {\n frontend: frontendUrl || undefined,\n api: apiUrl || undefined,\n },\n created: new Date(),\n location: 'remote',\n };\n\n saveWorkspaceMetadata(metadata);\n\n return metadata;\n}\n"],"mappings":"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","names":[]}