panopticon-cli 0.4.31 → 0.4.33

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 (138) hide show
  1. package/dist/{agents-GQDAKTEQ.js → agents-VLK4BMVA.js} +10 -7
  2. package/dist/chunk-7SN4L4PH.js +150 -0
  3. package/dist/chunk-7SN4L4PH.js.map +1 -0
  4. package/dist/chunk-7XNJJBH6.js +538 -0
  5. package/dist/chunk-7XNJJBH6.js.map +1 -0
  6. package/dist/chunk-AQXETQHW.js +113 -0
  7. package/dist/chunk-AQXETQHW.js.map +1 -0
  8. package/dist/{chunk-TMXN7THF.js → chunk-ASY7T35E.js} +170 -64
  9. package/dist/chunk-ASY7T35E.js.map +1 -0
  10. package/dist/chunk-B3PF6JPQ.js +212 -0
  11. package/dist/chunk-B3PF6JPQ.js.map +1 -0
  12. package/dist/{chunk-HNEWTIR3.js → chunk-BKCWRMUX.js} +100 -40
  13. package/dist/chunk-BKCWRMUX.js.map +1 -0
  14. package/dist/chunk-CFCUOV3Q.js +669 -0
  15. package/dist/chunk-CFCUOV3Q.js.map +1 -0
  16. package/dist/chunk-CWELWPWQ.js +32 -0
  17. package/dist/chunk-CWELWPWQ.js.map +1 -0
  18. package/dist/chunk-DI7ABPNQ.js +352 -0
  19. package/dist/chunk-DI7ABPNQ.js.map +1 -0
  20. package/dist/{chunk-VU4FLXV5.js → chunk-FQ66DECN.js} +31 -4
  21. package/dist/chunk-FQ66DECN.js.map +1 -0
  22. package/dist/{review-status-GWQYY77L.js → chunk-GFP3PIPB.js} +14 -7
  23. package/dist/chunk-GFP3PIPB.js.map +1 -0
  24. package/dist/chunk-JQBV3Q2W.js +29 -0
  25. package/dist/chunk-JQBV3Q2W.js.map +1 -0
  26. package/dist/{chunk-BWGFN44T.js → chunk-JT4O4YVM.js} +28 -16
  27. package/dist/chunk-JT4O4YVM.js.map +1 -0
  28. package/dist/{chunk-VIWUCJ4V.js → chunk-KJ2TRXNK.js} +34 -36
  29. package/dist/chunk-KJ2TRXNK.js.map +1 -0
  30. package/dist/{chunk-JY7R7V4G.js → chunk-OMNXYPXC.js} +2 -2
  31. package/dist/chunk-OMNXYPXC.js.map +1 -0
  32. package/dist/chunk-PELXV435.js +215 -0
  33. package/dist/chunk-PELXV435.js.map +1 -0
  34. package/dist/chunk-PI7Y3PSN.js +797 -0
  35. package/dist/chunk-PI7Y3PSN.js.map +1 -0
  36. package/dist/chunk-RBUO57TC.js +154 -0
  37. package/dist/chunk-RBUO57TC.js.map +1 -0
  38. package/dist/chunk-XFR2DLMR.js +600 -0
  39. package/dist/chunk-XFR2DLMR.js.map +1 -0
  40. package/dist/chunk-XKT5MHPT.js +677 -0
  41. package/dist/chunk-XKT5MHPT.js.map +1 -0
  42. package/dist/{chunk-HCTJFIJJ.js → chunk-YLPSQAM2.js} +2 -2
  43. package/dist/{chunk-HCTJFIJJ.js.map → chunk-YLPSQAM2.js.map} +1 -1
  44. package/dist/{chunk-6HXKTOD7.js → chunk-ZTFNYOC7.js} +53 -38
  45. package/dist/chunk-ZTFNYOC7.js.map +1 -0
  46. package/dist/cli/index.js +4362 -2922
  47. package/dist/cli/index.js.map +1 -1
  48. package/dist/{config-BOAMSKTF.js → config-4CJNUE3O.js} +7 -3
  49. package/dist/dashboard/prompts/merge-agent.md +217 -0
  50. package/dist/dashboard/prompts/review-agent.md +409 -0
  51. package/dist/dashboard/prompts/sync-main.md +84 -0
  52. package/dist/dashboard/prompts/test-agent.md +283 -0
  53. package/dist/dashboard/prompts/work-agent.md +247 -0
  54. package/dist/dashboard/public/assets/index-UjZq6ykz.css +32 -0
  55. package/dist/dashboard/public/assets/index-kAJqtLDO.js +708 -0
  56. package/dist/dashboard/public/index.html +2 -2
  57. package/dist/dashboard/server.js +15272 -3169
  58. package/dist/{dns-L3L2BB27.js → dns-7BDJSD3E.js} +4 -2
  59. package/dist/{feedback-writer-AAKF5BTK.js → feedback-writer-LVZ5TFYZ.js} +8 -4
  60. package/dist/feedback-writer-LVZ5TFYZ.js.map +1 -0
  61. package/dist/hume-WMAUBBV2.js +13 -0
  62. package/dist/index.d.ts +153 -40
  63. package/dist/index.js +65 -23
  64. package/dist/index.js.map +1 -1
  65. package/dist/{projects-VXRUCMLM.js → projects-JEIVIYC6.js} +3 -3
  66. package/dist/rally-RKFSWC7E.js +10 -0
  67. package/dist/{remote-agents-Z3R2A5BN.js → remote-agents-TFSMW7GN.js} +2 -2
  68. package/dist/{remote-workspace-2G6V2KNP.js → remote-workspace-AHVHQEES.js} +8 -8
  69. package/dist/review-status-EPFG4XM7.js +19 -0
  70. package/dist/shadow-state-5MDP6YXH.js +30 -0
  71. package/dist/shadow-state-5MDP6YXH.js.map +1 -0
  72. package/dist/{specialist-context-6SE5VRRC.js → specialist-context-T3NBMCIE.js} +8 -7
  73. package/dist/{specialist-context-6SE5VRRC.js.map → specialist-context-T3NBMCIE.js.map} +1 -1
  74. package/dist/{specialist-logs-EXLOQHQ2.js → specialist-logs-CVKD3YJ3.js} +7 -6
  75. package/dist/specialist-logs-CVKD3YJ3.js.map +1 -0
  76. package/dist/{specialists-BRUHPAXE.js → specialists-TKAP6T6Z.js} +7 -6
  77. package/dist/specialists-TKAP6T6Z.js.map +1 -0
  78. package/dist/tldr-daemon-T3THOUGT.js +21 -0
  79. package/dist/tldr-daemon-T3THOUGT.js.map +1 -0
  80. package/dist/traefik-QX4ZV4YG.js +19 -0
  81. package/dist/traefik-QX4ZV4YG.js.map +1 -0
  82. package/dist/tunnel-W2GZBLEV.js +13 -0
  83. package/dist/tunnel-W2GZBLEV.js.map +1 -0
  84. package/dist/workspace-manager-KLHUCIZV.js +22 -0
  85. package/dist/workspace-manager-KLHUCIZV.js.map +1 -0
  86. package/package.json +2 -2
  87. package/scripts/heartbeat-hook +37 -10
  88. package/scripts/patches/llm-tldr-tsx-support.py +109 -0
  89. package/scripts/pre-tool-hook +26 -15
  90. package/scripts/record-cost-event.js +177 -43
  91. package/scripts/record-cost-event.ts +87 -3
  92. package/scripts/statusline.sh +169 -0
  93. package/scripts/stop-hook +14 -11
  94. package/scripts/tldr-post-edit +72 -0
  95. package/scripts/tldr-read-enforcer +275 -0
  96. package/skills/check-merged/SKILL.md +143 -0
  97. package/skills/crash-investigation/SKILL.md +301 -0
  98. package/skills/github-cli/SKILL.md +185 -0
  99. package/skills/pan-reopen/SKILL.md +65 -0
  100. package/skills/pan-sync-main/SKILL.md +87 -0
  101. package/skills/pan-tldr/SKILL.md +149 -0
  102. package/skills/react-best-practices/SKILL.md +125 -0
  103. package/skills/spec-readiness/REPORT-TEMPLATE.md +158 -0
  104. package/skills/spec-readiness/SCORING-REFERENCE.md +369 -0
  105. package/skills/spec-readiness/SKILL.md +400 -0
  106. package/skills/spec-readiness-setup/SKILL.md +361 -0
  107. package/skills/workspace-status/SKILL.md +56 -0
  108. package/templates/traefik/dynamic/panopticon.yml.template +0 -5
  109. package/templates/traefik/traefik.yml +0 -8
  110. package/dist/chunk-3XAB4IXF.js +0 -51
  111. package/dist/chunk-3XAB4IXF.js.map +0 -1
  112. package/dist/chunk-6HXKTOD7.js.map +0 -1
  113. package/dist/chunk-BBCUK6N2.js +0 -241
  114. package/dist/chunk-BBCUK6N2.js.map +0 -1
  115. package/dist/chunk-BWGFN44T.js.map +0 -1
  116. package/dist/chunk-ELK6Q7QI.js +0 -545
  117. package/dist/chunk-ELK6Q7QI.js.map +0 -1
  118. package/dist/chunk-HNEWTIR3.js.map +0 -1
  119. package/dist/chunk-JY7R7V4G.js.map +0 -1
  120. package/dist/chunk-LYSBSZYV.js +0 -1523
  121. package/dist/chunk-LYSBSZYV.js.map +0 -1
  122. package/dist/chunk-TMXN7THF.js.map +0 -1
  123. package/dist/chunk-VIWUCJ4V.js.map +0 -1
  124. package/dist/chunk-VU4FLXV5.js.map +0 -1
  125. package/dist/dashboard/public/assets/index-C7X6LP5Z.css +0 -32
  126. package/dist/dashboard/public/assets/index-izWbAt7V.js +0 -645
  127. package/dist/feedback-writer-AAKF5BTK.js.map +0 -1
  128. package/dist/review-status-GWQYY77L.js.map +0 -1
  129. package/dist/traefik-CUJM6K5Z.js +0 -12
  130. /package/dist/{agents-GQDAKTEQ.js.map → agents-VLK4BMVA.js.map} +0 -0
  131. /package/dist/{config-BOAMSKTF.js.map → config-4CJNUE3O.js.map} +0 -0
  132. /package/dist/{dns-L3L2BB27.js.map → dns-7BDJSD3E.js.map} +0 -0
  133. /package/dist/{projects-VXRUCMLM.js.map → hume-WMAUBBV2.js.map} +0 -0
  134. /package/dist/{remote-agents-Z3R2A5BN.js.map → projects-JEIVIYC6.js.map} +0 -0
  135. /package/dist/{specialist-logs-EXLOQHQ2.js.map → rally-RKFSWC7E.js.map} +0 -0
  136. /package/dist/{specialists-BRUHPAXE.js.map → remote-agents-TFSMW7GN.js.map} +0 -0
  137. /package/dist/{remote-workspace-2G6V2KNP.js.map → remote-workspace-AHVHQEES.js.map} +0 -0
  138. /package/dist/{traefik-CUJM6K5Z.js.map → review-status-EPFG4XM7.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/shell.ts","../src/lib/backup.ts","../src/lib/sync.ts","../src/lib/tracker/linking.ts","../src/lib/tracker/index.ts"],"sourcesContent":["import { existsSync, readFileSync, appendFileSync } from 'fs';\nimport { homedir } from 'os';\nimport { join } from 'path';\n\nexport type Shell = 'bash' | 'zsh' | 'fish' | 'unknown';\n\nexport function detectShell(): Shell {\n const shell = process.env.SHELL || '';\n\n if (shell.includes('zsh')) return 'zsh';\n if (shell.includes('bash')) return 'bash';\n if (shell.includes('fish')) return 'fish';\n\n return 'unknown';\n}\n\nexport function getShellRcFile(shell: Shell): string | null {\n const home = homedir();\n\n switch (shell) {\n case 'zsh':\n return join(home, '.zshrc');\n case 'bash':\n // Prefer .bashrc, fall back to .bash_profile\n const bashrc = join(home, '.bashrc');\n if (existsSync(bashrc)) return bashrc;\n return join(home, '.bash_profile');\n case 'fish':\n return join(home, '.config', 'fish', 'config.fish');\n default:\n return null;\n }\n}\n\nconst ALIAS_LINE = 'alias pan=\"panopticon\"';\nconst ALIAS_MARKER = '# Panopticon CLI alias';\n\nexport function hasAlias(rcFile: string): boolean {\n if (!existsSync(rcFile)) return false;\n\n const content = readFileSync(rcFile, 'utf8');\n return content.includes(ALIAS_MARKER) || content.includes(ALIAS_LINE);\n}\n\nexport function addAlias(rcFile: string): void {\n if (hasAlias(rcFile)) return;\n\n const aliasBlock = `\n${ALIAS_MARKER}\n${ALIAS_LINE}\n`;\n\n appendFileSync(rcFile, aliasBlock, 'utf8');\n}\n\nexport function getAliasInstructions(shell: Shell): string {\n const rcFile = getShellRcFile(shell);\n\n if (!rcFile) {\n return `Add this to your shell config:\\n ${ALIAS_LINE}`;\n }\n\n return `Alias added to ${rcFile}. Run:\\n source ${rcFile}`;\n}\n","import { existsSync, mkdirSync, readdirSync, cpSync, rmSync, lstatSync } from 'fs';\nimport { join, basename } from 'path';\nimport { BACKUPS_DIR } from './paths.js';\n\nexport interface BackupInfo {\n timestamp: string;\n path: string;\n targets: string[];\n}\n\nexport function createBackupTimestamp(): string {\n return new Date().toISOString().replace(/[:.]/g, '-');\n}\n\nexport function createBackup(sourceDirs: string[]): BackupInfo {\n const timestamp = createBackupTimestamp();\n const backupPath = join(BACKUPS_DIR, timestamp);\n\n mkdirSync(backupPath, { recursive: true });\n\n const targets: string[] = [];\n\n for (const sourceDir of sourceDirs) {\n if (!existsSync(sourceDir)) continue;\n\n const targetName = basename(sourceDir);\n const targetPath = join(backupPath, targetName);\n\n // Use filter to skip symlinks — sync targets (e.g. ~/.claude/skills/)\n // contain symlinks back into ~/.panopticon/skills/ which causes cpSync\n // to fail with \"cannot copy to a subdirectory of self\".\n cpSync(sourceDir, targetPath, {\n recursive: true,\n filter: (src) => !lstatSync(src).isSymbolicLink(),\n });\n targets.push(targetName);\n }\n\n return {\n timestamp,\n path: backupPath,\n targets,\n };\n}\n\nexport function listBackups(): BackupInfo[] {\n if (!existsSync(BACKUPS_DIR)) return [];\n\n const entries = readdirSync(BACKUPS_DIR, { withFileTypes: true });\n\n return entries\n .filter((e) => e.isDirectory())\n .map((e) => {\n const backupPath = join(BACKUPS_DIR, e.name);\n const contents = readdirSync(backupPath);\n\n return {\n timestamp: e.name,\n path: backupPath,\n targets: contents,\n };\n })\n .sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n}\n\nexport function restoreBackup(timestamp: string, targetDirs: Record<string, string>): void {\n const backupPath = join(BACKUPS_DIR, timestamp);\n\n if (!existsSync(backupPath)) {\n throw new Error(`Backup not found: ${timestamp}`);\n }\n\n const contents = readdirSync(backupPath, { withFileTypes: true });\n\n for (const entry of contents) {\n if (!entry.isDirectory()) continue;\n\n const sourcePath = join(backupPath, entry.name);\n const targetPath = targetDirs[entry.name];\n\n if (!targetPath) continue;\n\n // Remove existing and restore from backup\n if (existsSync(targetPath)) {\n rmSync(targetPath, { recursive: true });\n }\n\n cpSync(sourcePath, targetPath, { recursive: true });\n }\n}\n\nexport function cleanOldBackups(keepCount: number = 10): number {\n const backups = listBackups();\n\n if (backups.length <= keepCount) return 0;\n\n const toRemove = backups.slice(keepCount);\n let removed = 0;\n\n for (const backup of toRemove) {\n rmSync(backup.path, { recursive: true });\n removed++;\n }\n\n return removed;\n}\n","import { existsSync, mkdirSync, readdirSync, symlinkSync, unlinkSync, lstatSync, readlinkSync, rmSync, copyFileSync, chmodSync, readFileSync, writeFileSync } from 'fs';\nimport { join, basename, dirname, relative } from 'path';\nimport { homedir } from 'os';\nimport {\n SKILLS_DIR, COMMANDS_DIR, AGENTS_DIR, BIN_DIR,\n SOURCE_SCRIPTS_DIR, SOURCE_DEV_SKILLS_DIR, SOURCE_SKILLS_DIR, SOURCE_AGENTS_DIR, SOURCE_RULES_DIR,\n CACHE_AGENTS_DIR, CACHE_RULES_DIR, CACHE_MANIFEST,\n SYNC_TARGET, isDevMode,\n} from './paths.js';\nimport {\n buildManifestFromDirectory, writeManifest, readManifest, hashFile,\n setManifestEntry, collectSourceFiles,\n type Manifest, type FileStatus,\n compareFileToManifest,\n} from './manifest.js';\nimport { getDevrootPath } from './config.js';\n\nexport interface SyncItem {\n name: string;\n sourcePath: string;\n targetPath: string;\n status: 'new' | 'exists' | 'conflict' | 'symlink';\n}\n\nexport interface SyncPlan {\n skills: SyncItem[];\n commands: SyncItem[];\n agents: SyncItem[];\n rules: SyncItem[];\n devSkills: SyncItem[]; // Developer-only skills (only synced in dev mode)\n}\n\n/**\n * Remove a file, symlink, or directory safely\n */\nfunction removeTarget(targetPath: string): void {\n const stats = lstatSync(targetPath);\n if (stats.isDirectory() && !stats.isSymbolicLink()) {\n // It's a real directory, remove recursively\n rmSync(targetPath, { recursive: true, force: true });\n } else {\n // It's a file or symlink\n unlinkSync(targetPath);\n }\n}\n\n/**\n * Check if a path is a Panopticon-managed symlink\n */\nexport function isPanopticonSymlink(targetPath: string): boolean {\n if (!existsSync(targetPath)) return false;\n\n try {\n const stats = lstatSync(targetPath);\n if (!stats.isSymbolicLink()) return false;\n\n const linkTarget = readlinkSync(targetPath);\n // It's ours if it points to our skills/commands dir\n return linkTarget.includes('.panopticon');\n } catch {\n return false;\n }\n}\n\nexport interface MigrationResult {\n removedSymlinks: string[];\n preservedUserContent: string[];\n errors: string[];\n}\n\n/**\n * One-time migration: remove Panopticon-managed symlinks from ~/.claude/.\n *\n * Detects symlinks in ~/.claude/skills/ and ~/.claude/agents/ that point to\n * .panopticon directories. Removes only those symlinks, preserving any\n * user-created content (real files/directories).\n *\n * This is safe to run multiple times — it's a no-op if no symlinks remain.\n */\nexport function migrateFromPersonalSymlinks(): MigrationResult {\n const claudeDir = join(homedir(), '.claude');\n const result: MigrationResult = {\n removedSymlinks: [],\n preservedUserContent: [],\n errors: [],\n };\n\n for (const subdir of ['skills', 'commands', 'agents']) {\n const dir = join(claudeDir, subdir);\n if (!existsSync(dir)) continue;\n\n try {\n const entries = readdirSync(dir);\n for (const entry of entries) {\n const entryPath = join(dir, entry);\n try {\n const stats = lstatSync(entryPath);\n if (stats.isSymbolicLink()) {\n const linkTarget = readlinkSync(entryPath);\n if (linkTarget.includes('.panopticon') || linkTarget.includes('panopticon-cli')) {\n unlinkSync(entryPath);\n result.removedSymlinks.push(`${subdir}/${entry}`);\n } else {\n // Symlink to somewhere else — leave it\n result.preservedUserContent.push(`${subdir}/${entry}`);\n }\n } else {\n // Real file/directory — user content, never touch\n result.preservedUserContent.push(`${subdir}/${entry}`);\n }\n } catch (err: any) {\n result.errors.push(`${subdir}/${entry}: ${err.message}`);\n }\n }\n } catch (err: any) {\n result.errors.push(`${subdir}: ${err.message}`);\n }\n }\n\n return result;\n}\n\nexport interface RefreshCacheResult {\n skills: { copied: number; total: number };\n agents: { copied: number; total: number };\n rules: { copied: number; total: number };\n}\n\n/**\n * Recursively copy a directory, overwriting existing files.\n */\nfunction copyDirectoryRecursive(source: string, dest: string): number {\n if (!existsSync(source)) return 0;\n\n mkdirSync(dest, { recursive: true });\n let count = 0;\n\n const entries = readdirSync(source, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = join(source, entry.name);\n const dstPath = join(dest, entry.name);\n if (entry.isDirectory()) {\n count += copyDirectoryRecursive(srcPath, dstPath);\n } else if (entry.isFile()) {\n copyFileSync(srcPath, dstPath);\n count++;\n }\n }\n return count;\n}\n\n/**\n * Refresh the ~/.panopticon/ cache from the repo source.\n *\n * Always copies (overwrites) skills, agents, and rules from the package's\n * source directories to the cache. Generates ~/.panopticon/.manifest.json\n * tracking all cached files.\n *\n * This replaces the old \"skip if exists\" behavior in `pan install`.\n */\nexport function refreshCache(): RefreshCacheResult {\n const result: RefreshCacheResult = {\n skills: { copied: 0, total: 0 },\n agents: { copied: 0, total: 0 },\n rules: { copied: 0, total: 0 },\n };\n\n // Copy skills from repo to cache (always overwrite)\n if (existsSync(SOURCE_SKILLS_DIR)) {\n const skillDirs = readdirSync(SOURCE_SKILLS_DIR, { withFileTypes: true })\n .filter((d) => d.isDirectory());\n\n result.skills.total = skillDirs.length;\n for (const skillDir of skillDirs) {\n const src = join(SOURCE_SKILLS_DIR, skillDir.name);\n const dst = join(SKILLS_DIR, skillDir.name);\n copyDirectoryRecursive(src, dst);\n result.skills.copied++;\n }\n }\n\n // Copy dev-skills to cache too (in dev mode only)\n if (isDevMode() && existsSync(SOURCE_DEV_SKILLS_DIR)) {\n const devSkillDirs = readdirSync(SOURCE_DEV_SKILLS_DIR, { withFileTypes: true })\n .filter((d) => d.isDirectory());\n\n for (const skillDir of devSkillDirs) {\n const src = join(SOURCE_DEV_SKILLS_DIR, skillDir.name);\n const dst = join(SKILLS_DIR, skillDir.name);\n copyDirectoryRecursive(src, dst);\n result.skills.copied++;\n result.skills.total++;\n }\n }\n\n // Copy agent definitions from repo to cache\n if (existsSync(SOURCE_AGENTS_DIR)) {\n mkdirSync(CACHE_AGENTS_DIR, { recursive: true });\n const agents = readdirSync(SOURCE_AGENTS_DIR, { withFileTypes: true })\n .filter((entry) => entry.isFile() && entry.name.endsWith('.md'));\n\n result.agents.total = agents.length;\n for (const agent of agents) {\n copyFileSync(join(SOURCE_AGENTS_DIR, agent.name), join(CACHE_AGENTS_DIR, agent.name));\n result.agents.copied++;\n }\n }\n\n // Copy rules from repo to cache (directory may not exist yet)\n if (existsSync(SOURCE_RULES_DIR)) {\n const ruleFiles = readdirSync(SOURCE_RULES_DIR, { withFileTypes: true })\n .filter((entry) => entry.isFile());\n\n result.rules.total = ruleFiles.length;\n for (const rule of ruleFiles) {\n mkdirSync(CACHE_RULES_DIR, { recursive: true });\n copyFileSync(join(SOURCE_RULES_DIR, rule.name), join(CACHE_RULES_DIR, rule.name));\n result.rules.copied++;\n }\n }\n\n // Generate cache manifest\n const manifest = buildManifestFromDirectory(\n join(SKILLS_DIR, '..'), // ~/.panopticon/\n ['skills', 'agent-definitions', 'rules'],\n 'panopticon',\n );\n writeManifest(CACHE_MANIFEST, manifest);\n\n return result;\n}\n\n/**\n * Devroot sync item — represents a single file to distribute.\n */\nexport interface DevrootSyncItem {\n /** Relative path from .claude/ (e.g., \"skills/beads/SKILL.md\") */\n relativePath: string;\n /** Absolute path to source file in cache */\n sourcePath: string;\n /** Absolute path to target file at devroot */\n targetPath: string;\n /** What action to take */\n status: FileStatus;\n}\n\n/**\n * Plan what would be synced to devroot (dry run).\n * Reads from cache, targets <devroot>/.claude/, uses manifest comparison.\n */\nexport function planSync(): SyncPlan {\n const plan: SyncPlan = {\n skills: [],\n commands: [],\n agents: [],\n rules: [],\n devSkills: [],\n };\n\n const devrootPath = getDevrootPath();\n if (!devrootPath) return plan;\n\n const targetBase = join(devrootPath, '.claude');\n const manifestPath = join(targetBase, '.panopticon-manifest.json');\n const manifest = readManifest(manifestPath);\n\n // Plan skills\n const skillFiles = collectSourceFiles(SKILLS_DIR, 'skills/');\n for (const file of skillFiles) {\n const targetFile = join(targetBase, file.relativePath);\n const status = compareFileToManifest(targetFile, file.relativePath, manifest);\n const skillName = file.relativePath.split('/')[1] || file.relativePath;\n\n let syncStatus: SyncItem['status'] = 'new';\n if (status.action === 'update') syncStatus = 'symlink'; // reusing 'symlink' for \"managed, safe to update\"\n else if (status.action === 'modified') syncStatus = 'conflict';\n else if (status.action === 'user-owned') syncStatus = 'conflict';\n\n plan.skills.push({\n name: file.relativePath,\n sourcePath: file.absolutePath,\n targetPath: targetFile,\n status: syncStatus,\n });\n }\n\n // Plan agents\n const agentFiles = collectSourceFiles(CACHE_AGENTS_DIR, 'agents/');\n for (const file of agentFiles) {\n const targetFile = join(targetBase, file.relativePath);\n const status = compareFileToManifest(targetFile, file.relativePath, manifest);\n\n let syncStatus: SyncItem['status'] = 'new';\n if (status.action === 'update') syncStatus = 'symlink';\n else if (status.action === 'modified') syncStatus = 'conflict';\n else if (status.action === 'user-owned') syncStatus = 'conflict';\n\n plan.agents.push({\n name: file.relativePath,\n sourcePath: file.absolutePath,\n targetPath: targetFile,\n status: syncStatus,\n });\n }\n\n // Plan rules\n const ruleFiles = collectSourceFiles(CACHE_RULES_DIR, 'rules/');\n for (const file of ruleFiles) {\n const targetFile = join(targetBase, file.relativePath);\n const status = compareFileToManifest(targetFile, file.relativePath, manifest);\n\n let syncStatus: SyncItem['status'] = 'new';\n if (status.action === 'update') syncStatus = 'symlink';\n else if (status.action === 'modified') syncStatus = 'conflict';\n else if (status.action === 'user-owned') syncStatus = 'conflict';\n\n plan.rules.push({\n name: file.relativePath,\n sourcePath: file.absolutePath,\n targetPath: targetFile,\n status: syncStatus,\n });\n }\n\n return plan;\n}\n\nexport interface SyncOptions {\n force?: boolean;\n diff?: boolean;\n dryRun?: boolean;\n}\n\nexport interface SyncResult {\n created: string[];\n updated: string[];\n skipped: string[];\n conflicts: string[];\n diffs: Array<{ path: string; sourceContent: string; targetContent: string }>;\n}\n\n/**\n * Execute sync to devroot: copy from cache to <devroot>/.claude/.\n * Uses manifest-based conflict resolution. NEVER touches ~/.claude/.\n */\nexport function executeSync(options: SyncOptions = {}): SyncResult {\n const result: SyncResult = {\n created: [],\n updated: [],\n skipped: [],\n conflicts: [],\n diffs: [],\n };\n\n const devrootPath = getDevrootPath();\n if (!devrootPath) {\n return result;\n }\n\n const targetBase = join(devrootPath, '.claude');\n const manifestPath = join(targetBase, '.panopticon-manifest.json');\n const manifest = readManifest(manifestPath);\n\n // Collect all source files from cache\n const allFiles = [\n ...collectSourceFiles(SKILLS_DIR, 'skills/'),\n ...collectSourceFiles(CACHE_AGENTS_DIR, 'agents/'),\n ...collectSourceFiles(CACHE_RULES_DIR, 'rules/'),\n ];\n\n for (const file of allFiles) {\n const targetFile = join(targetBase, file.relativePath);\n const status = compareFileToManifest(targetFile, file.relativePath, manifest);\n\n switch (status.action) {\n case 'new': {\n // File doesn't exist at target — copy it\n mkdirSync(dirname(targetFile), { recursive: true });\n copyFileSync(file.absolutePath, targetFile);\n const hash = hashFile(targetFile);\n setManifestEntry(manifest, file.relativePath, hash, 'panopticon');\n result.created.push(file.relativePath);\n break;\n }\n\n case 'update': {\n // File exists, hash matches manifest — safe to overwrite (user didn't modify)\n mkdirSync(dirname(targetFile), { recursive: true });\n copyFileSync(file.absolutePath, targetFile);\n const hash = hashFile(targetFile);\n setManifestEntry(manifest, file.relativePath, hash, 'panopticon');\n result.updated.push(file.relativePath);\n break;\n }\n\n case 'modified': {\n // File was modified since we placed it\n if (options.diff) {\n result.diffs.push({\n path: file.relativePath,\n sourceContent: readFileSync(file.absolutePath, 'utf-8'),\n targetContent: readFileSync(targetFile, 'utf-8'),\n });\n }\n\n if (options.force) {\n mkdirSync(dirname(targetFile), { recursive: true });\n copyFileSync(file.absolutePath, targetFile);\n const hash = hashFile(targetFile);\n setManifestEntry(manifest, file.relativePath, hash, 'panopticon');\n result.updated.push(file.relativePath);\n } else {\n result.conflicts.push(file.relativePath);\n }\n break;\n }\n\n case 'user-owned': {\n // User placed this file, never touch it\n result.skipped.push(file.relativePath);\n break;\n }\n }\n }\n\n // Write updated manifest\n writeManifest(manifestPath, manifest);\n\n return result;\n}\n\n/**\n * Hook item for sync planning\n */\nexport interface HookItem {\n name: string;\n sourcePath: string;\n targetPath: string;\n status: 'new' | 'updated' | 'current';\n}\n\n/**\n * Plan hooks sync (checks what would be updated)\n */\nexport function planHooksSync(): HookItem[] {\n const hooks: HookItem[] = [];\n\n if (!existsSync(SOURCE_SCRIPTS_DIR)) {\n return hooks;\n }\n\n // Sync hook scripts (no extension) and bundled JS scripts (.js)\n // Skip source files (.ts), shell helpers (.sh), and other non-hook files (.mjs)\n const scripts = readdirSync(SOURCE_SCRIPTS_DIR, { withFileTypes: true })\n .filter((entry) => entry.isFile() && !entry.name.startsWith('.')\n && (!entry.name.includes('.') || entry.name.endsWith('.js')));\n\n for (const script of scripts) {\n const sourcePath = join(SOURCE_SCRIPTS_DIR, script.name);\n const targetPath = join(BIN_DIR, script.name);\n\n let status: HookItem['status'] = 'new';\n\n if (existsSync(targetPath)) {\n // Could compare file contents/timestamps here for 'current' vs 'updated'\n // For now, always update to ensure latest version\n status = 'updated';\n }\n\n hooks.push({ name: script.name, sourcePath, targetPath, status });\n }\n\n return hooks;\n}\n\n/**\n * Sync hooks (copy scripts to ~/.panopticon/bin/)\n */\nexport function syncHooks(): { synced: string[]; errors: string[] } {\n const result = { synced: [] as string[], errors: [] as string[] };\n\n // Ensure bin directory exists\n mkdirSync(BIN_DIR, { recursive: true });\n\n const hooks = planHooksSync();\n\n for (const hook of hooks) {\n try {\n copyFileSync(hook.sourcePath, hook.targetPath);\n chmodSync(hook.targetPath, 0o755); // Make executable\n result.synced.push(hook.name);\n } catch (error) {\n result.errors.push(`${hook.name}: ${error}`);\n }\n }\n\n return result;\n}\n\n/**\n * Runtime-specific statusline configurations\n * Maps runtime to: config dir, statusline filename, settings file\n */\nconst STATUSLINE_TARGETS: Record<string, { configDir: string; scriptName: string; settingsFile: string }> = {\n claude: {\n configDir: join(homedir(), '.claude'),\n scriptName: 'statusline-command.sh',\n settingsFile: join(homedir(), '.claude', 'settings.json'),\n },\n // Other runtimes can be added as they support statusline\n};\n\n/**\n * Sync statusline script to all supported runtimes\n * Copies the canonical statusline.sh from panopticon scripts to each runtime's config dir\n * and ensures the runtime's settings.json references it.\n */\nexport function syncStatusline(): { synced: string[]; errors: string[] } {\n const result = { synced: [] as string[], errors: [] as string[] };\n\n const sourceScript = join(SOURCE_SCRIPTS_DIR, 'statusline.sh');\n if (!existsSync(sourceScript)) {\n return result;\n }\n\n for (const [runtime, target] of Object.entries(STATUSLINE_TARGETS)) {\n try {\n // Ensure config dir exists\n mkdirSync(target.configDir, { recursive: true });\n\n // Copy statusline script\n const targetScript = join(target.configDir, target.scriptName);\n copyFileSync(sourceScript, targetScript);\n chmodSync(targetScript, 0o755);\n\n // Update settings.json to reference the statusline\n updateSettingsStatusline(target.settingsFile, targetScript);\n\n result.synced.push(runtime);\n } catch (error) {\n result.errors.push(`${runtime}: ${error}`);\n }\n }\n\n return result;\n}\n\n/**\n * Update a settings.json file to include the statusLine configuration\n * Preserves all existing settings (hooks, etc.)\n */\nfunction updateSettingsStatusline(settingsFile: string, scriptPath: string): void {\n let settings: Record<string, any> = {};\n\n if (existsSync(settingsFile)) {\n try {\n settings = JSON.parse(readFileSync(settingsFile, 'utf-8'));\n } catch {\n // If settings file is corrupt, start fresh but preserve the file\n settings = {};\n }\n }\n\n // Only update if statusLine is missing or points to a different script\n const currentCommand = settings.statusLine?.command;\n if (currentCommand === scriptPath && settings.statusLine?.type === 'command') {\n return; // Already configured correctly\n }\n\n settings.statusLine = {\n type: 'command',\n command: scriptPath,\n padding: 0,\n };\n\n mkdirSync(dirname(settingsFile), { recursive: true });\n writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + '\\n', 'utf-8');\n}\n","/**\n * Cross-Tracker Linking\n *\n * Manages links between issues in different trackers.\n * Links are stored in a local JSON file for persistence.\n */\n\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport type { TrackerType } from './interface.js';\n\n// Link direction types\nexport type LinkDirection = 'blocks' | 'blocked_by' | 'related' | 'duplicate_of';\n\n// A single link between two issues\nexport interface TrackerLink {\n sourceIssueRef: string; // e.g., \"MIN-630\"\n sourceTracker: TrackerType;\n targetIssueRef: string; // e.g., \"#42\"\n targetTracker: TrackerType;\n direction: LinkDirection;\n createdAt: string; // ISO timestamp\n}\n\n// Storage format\ninterface LinkStore {\n version: 1;\n links: TrackerLink[];\n}\n\n/**\n * Parse an issue reference to extract tracker and ID\n * Examples:\n * \"#42\" -> { tracker: \"github\", ref: \"#42\" }\n * \"github#42\" -> { tracker: \"github\", ref: \"#42\" }\n * \"MIN-630\" -> { tracker: \"linear\", ref: \"MIN-630\" }\n * \"gitlab#15\" -> { tracker: \"gitlab\", ref: \"#15\" }\n */\nexport function parseIssueRef(ref: string): { tracker: TrackerType; ref: string } | null {\n // Explicit tracker prefix\n if (ref.startsWith('github#')) {\n return { tracker: 'github', ref: `#${ref.slice(7)}` };\n }\n if (ref.startsWith('gitlab#')) {\n return { tracker: 'gitlab', ref: `#${ref.slice(7)}` };\n }\n if (ref.startsWith('linear:')) {\n return { tracker: 'linear', ref: ref.slice(7) };\n }\n\n // GitHub-style refs (#number)\n if (/^#\\d+$/.test(ref)) {\n return { tracker: 'github', ref };\n }\n\n // Linear-style refs (XXX-123)\n if (/^[A-Z]+-\\d+$/i.test(ref)) {\n return { tracker: 'linear', ref: ref.toUpperCase() };\n }\n\n return null;\n}\n\n/**\n * Format an issue ref with tracker prefix for display\n */\nexport function formatIssueRef(ref: string, tracker: TrackerType): string {\n if (tracker === 'github') {\n return ref.startsWith('#') ? `github${ref}` : `github#${ref}`;\n }\n if (tracker === 'gitlab') {\n return ref.startsWith('#') ? `gitlab${ref}` : `gitlab#${ref}`;\n }\n return ref; // Linear refs are already unique\n}\n\n/**\n * Link Manager for cross-tracker issue linking\n */\nexport class LinkManager {\n private storePath: string;\n private store: LinkStore;\n\n constructor(storePath?: string) {\n this.storePath = storePath ?? join(homedir(), '.panopticon', 'links.json');\n this.store = this.load();\n }\n\n private load(): LinkStore {\n if (existsSync(this.storePath)) {\n try {\n const data = JSON.parse(readFileSync(this.storePath, 'utf-8'));\n if (data.version === 1) {\n return data;\n }\n } catch {\n // Fall through to default\n }\n }\n return { version: 1, links: [] };\n }\n\n private save(): void {\n const dir = join(this.storePath, '..');\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(this.storePath, JSON.stringify(this.store, null, 2));\n }\n\n /**\n * Add a link between two issues\n */\n addLink(\n source: { ref: string; tracker: TrackerType },\n target: { ref: string; tracker: TrackerType },\n direction: LinkDirection = 'related'\n ): TrackerLink {\n // Check if link already exists\n const existing = this.store.links.find(\n (l) =>\n l.sourceIssueRef === source.ref &&\n l.sourceTracker === source.tracker &&\n l.targetIssueRef === target.ref &&\n l.targetTracker === target.tracker\n );\n\n if (existing) {\n // Update direction if different\n if (existing.direction !== direction) {\n existing.direction = direction;\n this.save();\n }\n return existing;\n }\n\n const link: TrackerLink = {\n sourceIssueRef: source.ref,\n sourceTracker: source.tracker,\n targetIssueRef: target.ref,\n targetTracker: target.tracker,\n direction,\n createdAt: new Date().toISOString(),\n };\n\n this.store.links.push(link);\n this.save();\n return link;\n }\n\n /**\n * Remove a link between two issues\n */\n removeLink(\n source: { ref: string; tracker: TrackerType },\n target: { ref: string; tracker: TrackerType }\n ): boolean {\n const index = this.store.links.findIndex(\n (l) =>\n l.sourceIssueRef === source.ref &&\n l.sourceTracker === source.tracker &&\n l.targetIssueRef === target.ref &&\n l.targetTracker === target.tracker\n );\n\n if (index >= 0) {\n this.store.links.splice(index, 1);\n this.save();\n return true;\n }\n return false;\n }\n\n /**\n * Get all issues linked to a given issue\n */\n getLinkedIssues(ref: string, tracker: TrackerType): TrackerLink[] {\n return this.store.links.filter(\n (l) =>\n (l.sourceIssueRef === ref && l.sourceTracker === tracker) ||\n (l.targetIssueRef === ref && l.targetTracker === tracker)\n );\n }\n\n /**\n * Get all links (for debugging/admin)\n */\n getAllLinks(): TrackerLink[] {\n return [...this.store.links];\n }\n\n /**\n * Find linked issue in another tracker\n */\n findLinkedIssue(\n ref: string,\n sourceTracker: TrackerType,\n targetTracker: TrackerType\n ): string | null {\n // Check as source\n const asSource = this.store.links.find(\n (l) =>\n l.sourceIssueRef === ref &&\n l.sourceTracker === sourceTracker &&\n l.targetTracker === targetTracker\n );\n if (asSource) return asSource.targetIssueRef;\n\n // Check as target\n const asTarget = this.store.links.find(\n (l) =>\n l.targetIssueRef === ref &&\n l.targetTracker === sourceTracker &&\n l.sourceTracker === targetTracker\n );\n if (asTarget) return asTarget.sourceIssueRef;\n\n return null;\n }\n\n /**\n * Clear all links (for testing)\n */\n clear(): void {\n this.store.links = [];\n this.save();\n }\n}\n\n// Singleton instance\nlet _linkManager: LinkManager | null = null;\n\nexport function getLinkManager(): LinkManager {\n if (!_linkManager) {\n _linkManager = new LinkManager();\n }\n return _linkManager;\n}\n","/**\n * Issue Tracker Module\n *\n * Provides a unified interface for different issue tracking systems.\n */\n\n// Core interface and types\nexport type {\n IssueTracker,\n Issue,\n IssueFilters,\n IssueState,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\n\nexport {\n NotImplementedError,\n IssueNotFoundError,\n TrackerAuthError,\n} from './interface.js';\n\n// Tracker implementations\nexport { LinearTracker } from './linear.js';\nexport { GitHubTracker } from './github.js';\nexport { GitLabTracker } from './gitlab.js';\n\n// Factory functions\nexport type { TrackerConfig } from './factory.js';\nexport {\n createTracker,\n createTrackerFromConfig,\n getPrimaryTracker,\n getSecondaryTracker,\n getAllTrackers,\n} from './factory.js';\n\n// Cross-tracker linking\nexport type { TrackerLink, LinkDirection } from './linking.js';\nexport {\n LinkManager,\n getLinkManager,\n parseIssueRef,\n formatIssueRef,\n} from './linking.js';\n"],"mappings":"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","names":["existsSync","join","existsSync","mkdirSync","readdirSync","lstatSync","rmSync","readFileSync","join","homedir","existsSync","lstatSync","join","homedir","readdirSync","mkdirSync","readFileSync","readFileSync","writeFileSync","existsSync","mkdirSync","join","homedir"]}
@@ -35,7 +35,7 @@ async function remoteSessionExists(exe, vmName, sessionName) {
35
35
  return result.stdout.trim() === "exists";
36
36
  }
37
37
  async function spawnRemoteAgent(options) {
38
- const { issueId, workspace, model = "claude-sonnet-4-5", prompt } = options;
38
+ const { issueId, workspace, model = "claude-sonnet-4-6", prompt } = options;
39
39
  const agentId = `agent-${issueId.toLowerCase()}`;
40
40
  const vmName = workspace.vmName;
41
41
  const exe = createExeProvider({ infraVm: workspace.infraVm });
@@ -156,4 +156,4 @@ export {
156
156
  pollRemoteAgentStatus,
157
157
  init_remote_agents
158
158
  };
159
- //# sourceMappingURL=chunk-HCTJFIJJ.js.map
159
+ //# sourceMappingURL=chunk-YLPSQAM2.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/remote/remote-agents.ts"],"sourcesContent":["/**\n * Remote Agent Management\n *\n * Spawn and manage Claude agents on remote exe.dev VMs.\n * Agents run in tmux sessions for persistence and monitoring.\n */\n\nimport { ExeProvider, createExeProvider } from './exe-provider.js';\nimport type { RemoteWorkspaceMetadata } from './interface.js';\nimport { join } from 'path';\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { homedir } from 'os';\n\nconst AGENTS_DIR = join(homedir(), '.panopticon', 'agents');\n\nexport interface RemoteAgentState {\n id: string;\n issueId: string;\n vmName: string;\n model: string;\n status: 'starting' | 'running' | 'stopped' | 'error';\n startedAt: string;\n lastActivity?: string;\n location: 'remote';\n}\n\n/**\n * Get agent state file path\n */\nfunction getRemoteAgentStateFile(agentId: string): string {\n return join(AGENTS_DIR, agentId, 'remote-state.json');\n}\n\n/**\n * Save remote agent state\n */\nfunction saveRemoteAgentState(state: RemoteAgentState): void {\n const dir = join(AGENTS_DIR, state.id);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(getRemoteAgentStateFile(state.id), JSON.stringify(state, null, 2));\n}\n\n/**\n * Load remote agent state\n */\nexport function loadRemoteAgentState(agentId: string): RemoteAgentState | null {\n const file = getRemoteAgentStateFile(agentId);\n if (!existsSync(file)) return null;\n\n try {\n return JSON.parse(readFileSync(file, 'utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Check if remote agent session exists\n */\nasync function remoteSessionExists(\n exe: ExeProvider,\n vmName: string,\n sessionName: string\n): Promise<boolean> {\n const result = await exe.ssh(vmName, `tmux has-session -t ${sessionName} 2>/dev/null && echo exists || echo not-found`);\n return result.stdout.trim() === 'exists';\n}\n\nexport interface SpawnRemoteAgentOptions {\n issueId: string;\n workspace: RemoteWorkspaceMetadata;\n model?: string;\n prompt?: string;\n phase?: string;\n}\n\n/**\n * Spawn a Claude agent on a remote VM\n */\nexport async function spawnRemoteAgent(options: SpawnRemoteAgentOptions): Promise<RemoteAgentState> {\n const { issueId, workspace, model = 'claude-sonnet-4-5', prompt } = options;\n\n const agentId = `agent-${issueId.toLowerCase()}`;\n const vmName = workspace.vmName;\n\n const exe = createExeProvider({ infraVm: workspace.infraVm });\n\n // Check if VM is running\n const vmStatus = await exe.getStatus(vmName);\n if (vmStatus !== 'running') {\n throw new Error(`VM ${vmName} is not running. Start it with: pan workspace start ${issueId}`);\n }\n\n // Check if agent already exists\n if (await remoteSessionExists(exe, vmName, agentId)) {\n throw new Error(`Agent ${agentId} already running on ${vmName}. Use 'pan work tell' to message it.`);\n }\n\n // Create agent state\n const state: RemoteAgentState = {\n id: agentId,\n issueId,\n vmName,\n model,\n status: 'starting',\n startedAt: new Date().toISOString(),\n location: 'remote',\n };\n\n saveRemoteAgentState(state);\n\n // Write prompt to file on remote VM if provided\n let claudeCmd: string;\n\n if (prompt) {\n // Write prompt to file on VM using base64 to avoid escaping issues\n const promptFile = `/workspace/.panopticon/prompts/${agentId}.md`;\n await exe.ssh(vmName, `mkdir -p /workspace/.panopticon/prompts`);\n const promptBase64 = Buffer.from(prompt).toString('base64');\n await exe.ssh(vmName, `echo '${promptBase64}' | base64 -d > ${promptFile}`);\n\n // Create launcher script using base64 to avoid shell interpretation\n const launcherScript = `/workspace/.panopticon/prompts/${agentId}-launcher.sh`;\n const launcherContent = `#!/bin/bash\nexport PATH=\"/usr/local/bin:\\$PATH\"\nprompt=\\$(cat \"${promptFile}\")\nexec claude --dangerously-skip-permissions --model ${model} \"\\$prompt\"\n`;\n const launcherBase64 = Buffer.from(launcherContent).toString('base64');\n await exe.ssh(vmName, `echo '${launcherBase64}' | base64 -d > ${launcherScript} && chmod +x ${launcherScript}`);\n\n claudeCmd = `bash ${launcherScript}`;\n } else {\n claudeCmd = `claude --dangerously-skip-permissions --model ${model}`;\n }\n\n // Create tmux session on remote VM\n const tmuxCmd = `tmux new-session -d -s ${agentId} -c /workspace '${claudeCmd}'`;\n const result = await exe.ssh(vmName, tmuxCmd);\n\n if (result.exitCode !== 0) {\n state.status = 'error';\n saveRemoteAgentState(state);\n throw new Error(`Failed to start agent: ${result.stderr}`);\n }\n\n // Update status\n state.status = 'running';\n saveRemoteAgentState(state);\n\n return state;\n}\n\n/**\n * Get remote agent output from tmux session\n */\nexport async function getRemoteAgentOutput(\n agentId: string,\n vmName: string,\n lines: number = 100\n): Promise<string> {\n const exe = createExeProvider();\n\n const result = await exe.ssh(vmName, `tmux capture-pane -t ${agentId} -p -S -${lines}`);\n return result.stdout;\n}\n\n/**\n * Send message to remote agent\n */\nexport async function sendToRemoteAgent(\n agentId: string,\n vmName: string,\n message: string\n): Promise<void> {\n const exe = createExeProvider();\n\n // Escape message for shell\n const escapedMessage = message.replace(/'/g, \"'\\\\''\");\n\n // Send keys to tmux session (send message then Enter)\n await exe.ssh(vmName, `tmux send-keys -t ${agentId} '${escapedMessage}'`);\n await exe.ssh(vmName, `tmux send-keys -t ${agentId} C-m`);\n}\n\n/**\n * Check if remote agent is still running\n */\nexport async function isRemoteAgentRunning(\n agentId: string,\n vmName: string\n): Promise<boolean> {\n const exe = createExeProvider();\n return remoteSessionExists(exe, vmName, agentId);\n}\n\n/**\n * Kill remote agent session\n */\nexport async function killRemoteAgent(\n agentId: string,\n vmName: string\n): Promise<void> {\n const exe = createExeProvider();\n await exe.ssh(vmName, `tmux kill-session -t ${agentId} 2>/dev/null || true`);\n\n // Update state\n const state = loadRemoteAgentState(agentId);\n if (state) {\n state.status = 'stopped';\n saveRemoteAgentState(state);\n }\n}\n\n/**\n * Get list of running remote agents on a VM\n */\nexport async function listRemoteAgents(vmName: string): Promise<string[]> {\n const exe = createExeProvider();\n\n const result = await exe.ssh(vmName, `tmux list-sessions -F \"#{session_name}\" 2>/dev/null | grep \"^agent-\" || true`);\n if (!result.stdout.trim()) {\n return [];\n }\n\n return result.stdout.trim().split('\\n').filter(Boolean);\n}\n\n/**\n * Poll remote agent for status updates\n * Returns parsed events from the agent output\n */\nexport async function pollRemoteAgentStatus(\n agentId: string,\n vmName: string\n): Promise<{\n isRunning: boolean;\n lastOutput: string;\n toolUses: string[];\n}> {\n const exe = createExeProvider();\n\n // Check if session exists\n const isRunning = await remoteSessionExists(exe, vmName, agentId);\n\n if (!isRunning) {\n return { isRunning: false, lastOutput: '', toolUses: [] };\n }\n\n // Get recent output\n const output = await getRemoteAgentOutput(agentId, vmName, 50);\n\n // Parse tool uses from output (simple pattern matching)\n const toolUses: string[] = [];\n const toolPattern = /(?:Using|Calling|Running)\\s+(\\w+)\\s+tool/gi;\n let match;\n while ((match = toolPattern.exec(output)) !== null) {\n toolUses.push(match[1]);\n }\n\n return {\n isRunning,\n lastOutput: output,\n toolUses,\n };\n}\n"],"mappings":";;;;;;;;;;AASA,SAAS,YAAY;AACrB,SAAS,YAAY,cAAc,eAAe,iBAAiB;AACnE,SAAS,eAAe;AAkBxB,SAAS,wBAAwB,SAAyB;AACxD,SAAO,KAAK,YAAY,SAAS,mBAAmB;AACtD;AAKA,SAAS,qBAAqB,OAA+B;AAC3D,QAAM,MAAM,KAAK,YAAY,MAAM,EAAE;AACrC,MAAI,CAAC,WAAW,GAAG,GAAG;AACpB,cAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EACpC;AACA,gBAAc,wBAAwB,MAAM,EAAE,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AACjF;AAKO,SAAS,qBAAqB,SAA0C;AAC7E,QAAM,OAAO,wBAAwB,OAAO;AAC5C,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO;AAE9B,MAAI;AACF,WAAO,KAAK,MAAM,aAAa,MAAM,OAAO,CAAC;AAAA,EAC/C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKA,eAAe,oBACb,KACA,QACA,aACkB;AAClB,QAAM,SAAS,MAAM,IAAI,IAAI,QAAQ,uBAAuB,WAAW,+CAA+C;AACtH,SAAO,OAAO,OAAO,KAAK,MAAM;AAClC;AAaA,eAAsB,iBAAiB,SAA6D;AAClG,QAAM,EAAE,SAAS,WAAW,QAAQ,qBAAqB,OAAO,IAAI;AAEpE,QAAM,UAAU,SAAS,QAAQ,YAAY,CAAC;AAC9C,QAAM,SAAS,UAAU;AAEzB,QAAM,MAAM,kBAAkB,EAAE,SAAS,UAAU,QAAQ,CAAC;AAG5D,QAAM,WAAW,MAAM,IAAI,UAAU,MAAM;AAC3C,MAAI,aAAa,WAAW;AAC1B,UAAM,IAAI,MAAM,MAAM,MAAM,uDAAuD,OAAO,EAAE;AAAA,EAC9F;AAGA,MAAI,MAAM,oBAAoB,KAAK,QAAQ,OAAO,GAAG;AACnD,UAAM,IAAI,MAAM,SAAS,OAAO,uBAAuB,MAAM,sCAAsC;AAAA,EACrG;AAGA,QAAM,QAA0B;AAAA,IAC9B,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,UAAU;AAAA,EACZ;AAEA,uBAAqB,KAAK;AAG1B,MAAI;AAEJ,MAAI,QAAQ;AAEV,UAAM,aAAa,kCAAkC,OAAO;AAC5D,UAAM,IAAI,IAAI,QAAQ,yCAAyC;AAC/D,UAAM,eAAe,OAAO,KAAK,MAAM,EAAE,SAAS,QAAQ;AAC1D,UAAM,IAAI,IAAI,QAAQ,SAAS,YAAY,mBAAmB,UAAU,EAAE;AAG1E,UAAM,iBAAiB,kCAAkC,OAAO;AAChE,UAAM,kBAAkB;AAAA;AAAA,gBAEX,UAAU;AAAA,qDAC0B,KAAK;AAAA;AAEtD,UAAM,iBAAiB,OAAO,KAAK,eAAe,EAAE,SAAS,QAAQ;AACrE,UAAM,IAAI,IAAI,QAAQ,SAAS,cAAc,mBAAmB,cAAc,gBAAgB,cAAc,EAAE;AAE9G,gBAAY,QAAQ,cAAc;AAAA,EACpC,OAAO;AACL,gBAAY,iDAAiD,KAAK;AAAA,EACpE;AAGA,QAAM,UAAU,0BAA0B,OAAO,mBAAmB,SAAS;AAC7E,QAAM,SAAS,MAAM,IAAI,IAAI,QAAQ,OAAO;AAE5C,MAAI,OAAO,aAAa,GAAG;AACzB,UAAM,SAAS;AACf,yBAAqB,KAAK;AAC1B,UAAM,IAAI,MAAM,0BAA0B,OAAO,MAAM,EAAE;AAAA,EAC3D;AAGA,QAAM,SAAS;AACf,uBAAqB,KAAK;AAE1B,SAAO;AACT;AAKA,eAAsB,qBACpB,SACA,QACA,QAAgB,KACC;AACjB,QAAM,MAAM,kBAAkB;AAE9B,QAAM,SAAS,MAAM,IAAI,IAAI,QAAQ,wBAAwB,OAAO,WAAW,KAAK,EAAE;AACtF,SAAO,OAAO;AAChB;AAKA,eAAsB,kBACpB,SACA,QACA,SACe;AACf,QAAM,MAAM,kBAAkB;AAG9B,QAAM,iBAAiB,QAAQ,QAAQ,MAAM,OAAO;AAGpD,QAAM,IAAI,IAAI,QAAQ,qBAAqB,OAAO,KAAK,cAAc,GAAG;AACxE,QAAM,IAAI,IAAI,QAAQ,qBAAqB,OAAO,MAAM;AAC1D;AAKA,eAAsB,qBACpB,SACA,QACkB;AAClB,QAAM,MAAM,kBAAkB;AAC9B,SAAO,oBAAoB,KAAK,QAAQ,OAAO;AACjD;AAKA,eAAsB,gBACpB,SACA,QACe;AACf,QAAM,MAAM,kBAAkB;AAC9B,QAAM,IAAI,IAAI,QAAQ,wBAAwB,OAAO,sBAAsB;AAG3E,QAAM,QAAQ,qBAAqB,OAAO;AAC1C,MAAI,OAAO;AACT,UAAM,SAAS;AACf,yBAAqB,KAAK;AAAA,EAC5B;AACF;AAKA,eAAsB,iBAAiB,QAAmC;AACxE,QAAM,MAAM,kBAAkB;AAE9B,QAAM,SAAS,MAAM,IAAI,IAAI,QAAQ,8EAA8E;AACnH,MAAI,CAAC,OAAO,OAAO,KAAK,GAAG;AACzB,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,OAAO,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACxD;AAMA,eAAsB,sBACpB,SACA,QAKC;AACD,QAAM,MAAM,kBAAkB;AAG9B,QAAM,YAAY,MAAM,oBAAoB,KAAK,QAAQ,OAAO;AAEhE,MAAI,CAAC,WAAW;AACd,WAAO,EAAE,WAAW,OAAO,YAAY,IAAI,UAAU,CAAC,EAAE;AAAA,EAC1D;AAGA,QAAM,SAAS,MAAM,qBAAqB,SAAS,QAAQ,EAAE;AAG7D,QAAM,WAAqB,CAAC;AAC5B,QAAM,cAAc;AACpB,MAAI;AACJ,UAAQ,QAAQ,YAAY,KAAK,MAAM,OAAO,MAAM;AAClD,aAAS,KAAK,MAAM,CAAC,CAAC;AAAA,EACxB;AAEA,SAAO;AAAA,IACL;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,EACF;AACF;AA3QA,IAaM;AAbN;AAAA;AAAA;AAOA;AAMA,IAAM,aAAa,KAAK,QAAQ,GAAG,eAAe,QAAQ;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../src/lib/remote/remote-agents.ts"],"sourcesContent":["/**\n * Remote Agent Management\n *\n * Spawn and manage Claude agents on remote exe.dev VMs.\n * Agents run in tmux sessions for persistence and monitoring.\n */\n\nimport { ExeProvider, createExeProvider } from './exe-provider.js';\nimport type { RemoteWorkspaceMetadata } from './interface.js';\nimport { join } from 'path';\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { homedir } from 'os';\n\nconst AGENTS_DIR = join(homedir(), '.panopticon', 'agents');\n\nexport interface RemoteAgentState {\n id: string;\n issueId: string;\n vmName: string;\n model: string;\n status: 'starting' | 'running' | 'stopped' | 'error';\n startedAt: string;\n lastActivity?: string;\n location: 'remote';\n}\n\n/**\n * Get agent state file path\n */\nfunction getRemoteAgentStateFile(agentId: string): string {\n return join(AGENTS_DIR, agentId, 'remote-state.json');\n}\n\n/**\n * Save remote agent state\n */\nfunction saveRemoteAgentState(state: RemoteAgentState): void {\n const dir = join(AGENTS_DIR, state.id);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(getRemoteAgentStateFile(state.id), JSON.stringify(state, null, 2));\n}\n\n/**\n * Load remote agent state\n */\nexport function loadRemoteAgentState(agentId: string): RemoteAgentState | null {\n const file = getRemoteAgentStateFile(agentId);\n if (!existsSync(file)) return null;\n\n try {\n return JSON.parse(readFileSync(file, 'utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Check if remote agent session exists\n */\nasync function remoteSessionExists(\n exe: ExeProvider,\n vmName: string,\n sessionName: string\n): Promise<boolean> {\n const result = await exe.ssh(vmName, `tmux has-session -t ${sessionName} 2>/dev/null && echo exists || echo not-found`);\n return result.stdout.trim() === 'exists';\n}\n\nexport interface SpawnRemoteAgentOptions {\n issueId: string;\n workspace: RemoteWorkspaceMetadata;\n model?: string;\n prompt?: string;\n phase?: string;\n}\n\n/**\n * Spawn a Claude agent on a remote VM\n */\nexport async function spawnRemoteAgent(options: SpawnRemoteAgentOptions): Promise<RemoteAgentState> {\n const { issueId, workspace, model = 'claude-sonnet-4-6', prompt } = options;\n\n const agentId = `agent-${issueId.toLowerCase()}`;\n const vmName = workspace.vmName;\n\n const exe = createExeProvider({ infraVm: workspace.infraVm });\n\n // Check if VM is running\n const vmStatus = await exe.getStatus(vmName);\n if (vmStatus !== 'running') {\n throw new Error(`VM ${vmName} is not running. Start it with: pan workspace start ${issueId}`);\n }\n\n // Check if agent already exists\n if (await remoteSessionExists(exe, vmName, agentId)) {\n throw new Error(`Agent ${agentId} already running on ${vmName}. Use 'pan work tell' to message it.`);\n }\n\n // Create agent state\n const state: RemoteAgentState = {\n id: agentId,\n issueId,\n vmName,\n model,\n status: 'starting',\n startedAt: new Date().toISOString(),\n location: 'remote',\n };\n\n saveRemoteAgentState(state);\n\n // Write prompt to file on remote VM if provided\n let claudeCmd: string;\n\n if (prompt) {\n // Write prompt to file on VM using base64 to avoid escaping issues\n const promptFile = `/workspace/.panopticon/prompts/${agentId}.md`;\n await exe.ssh(vmName, `mkdir -p /workspace/.panopticon/prompts`);\n const promptBase64 = Buffer.from(prompt).toString('base64');\n await exe.ssh(vmName, `echo '${promptBase64}' | base64 -d > ${promptFile}`);\n\n // Create launcher script using base64 to avoid shell interpretation\n const launcherScript = `/workspace/.panopticon/prompts/${agentId}-launcher.sh`;\n const launcherContent = `#!/bin/bash\nexport PATH=\"/usr/local/bin:\\$PATH\"\nprompt=\\$(cat \"${promptFile}\")\nexec claude --dangerously-skip-permissions --model ${model} \"\\$prompt\"\n`;\n const launcherBase64 = Buffer.from(launcherContent).toString('base64');\n await exe.ssh(vmName, `echo '${launcherBase64}' | base64 -d > ${launcherScript} && chmod +x ${launcherScript}`);\n\n claudeCmd = `bash ${launcherScript}`;\n } else {\n claudeCmd = `claude --dangerously-skip-permissions --model ${model}`;\n }\n\n // Create tmux session on remote VM\n const tmuxCmd = `tmux new-session -d -s ${agentId} -c /workspace '${claudeCmd}'`;\n const result = await exe.ssh(vmName, tmuxCmd);\n\n if (result.exitCode !== 0) {\n state.status = 'error';\n saveRemoteAgentState(state);\n throw new Error(`Failed to start agent: ${result.stderr}`);\n }\n\n // Update status\n state.status = 'running';\n saveRemoteAgentState(state);\n\n return state;\n}\n\n/**\n * Get remote agent output from tmux session\n */\nexport async function getRemoteAgentOutput(\n agentId: string,\n vmName: string,\n lines: number = 100\n): Promise<string> {\n const exe = createExeProvider();\n\n const result = await exe.ssh(vmName, `tmux capture-pane -t ${agentId} -p -S -${lines}`);\n return result.stdout;\n}\n\n/**\n * Send message to remote agent\n */\nexport async function sendToRemoteAgent(\n agentId: string,\n vmName: string,\n message: string\n): Promise<void> {\n const exe = createExeProvider();\n\n // Escape message for shell\n const escapedMessage = message.replace(/'/g, \"'\\\\''\");\n\n // Send keys to tmux session (send message then Enter)\n await exe.ssh(vmName, `tmux send-keys -t ${agentId} '${escapedMessage}'`);\n await exe.ssh(vmName, `tmux send-keys -t ${agentId} C-m`);\n}\n\n/**\n * Check if remote agent is still running\n */\nexport async function isRemoteAgentRunning(\n agentId: string,\n vmName: string\n): Promise<boolean> {\n const exe = createExeProvider();\n return remoteSessionExists(exe, vmName, agentId);\n}\n\n/**\n * Kill remote agent session\n */\nexport async function killRemoteAgent(\n agentId: string,\n vmName: string\n): Promise<void> {\n const exe = createExeProvider();\n await exe.ssh(vmName, `tmux kill-session -t ${agentId} 2>/dev/null || true`);\n\n // Update state\n const state = loadRemoteAgentState(agentId);\n if (state) {\n state.status = 'stopped';\n saveRemoteAgentState(state);\n }\n}\n\n/**\n * Get list of running remote agents on a VM\n */\nexport async function listRemoteAgents(vmName: string): Promise<string[]> {\n const exe = createExeProvider();\n\n const result = await exe.ssh(vmName, `tmux list-sessions -F \"#{session_name}\" 2>/dev/null | grep \"^agent-\" || true`);\n if (!result.stdout.trim()) {\n return [];\n }\n\n return result.stdout.trim().split('\\n').filter(Boolean);\n}\n\n/**\n * Poll remote agent for status updates\n * Returns parsed events from the agent output\n */\nexport async function pollRemoteAgentStatus(\n agentId: string,\n vmName: string\n): Promise<{\n isRunning: boolean;\n lastOutput: string;\n toolUses: string[];\n}> {\n const exe = createExeProvider();\n\n // Check if session exists\n const isRunning = await remoteSessionExists(exe, vmName, agentId);\n\n if (!isRunning) {\n return { isRunning: false, lastOutput: '', toolUses: [] };\n }\n\n // Get recent output\n const output = await getRemoteAgentOutput(agentId, vmName, 50);\n\n // Parse tool uses from output (simple pattern matching)\n const toolUses: string[] = [];\n const toolPattern = /(?:Using|Calling|Running)\\s+(\\w+)\\s+tool/gi;\n let match;\n while ((match = toolPattern.exec(output)) !== null) {\n toolUses.push(match[1]);\n }\n\n return {\n isRunning,\n lastOutput: output,\n toolUses,\n };\n}\n"],"mappings":"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","names":[]}
@@ -19,7 +19,7 @@ function isDevMode() {
19
19
  return false;
20
20
  }
21
21
  }
22
- var PANOPTICON_HOME, CONFIG_DIR, SKILLS_DIR, COMMANDS_DIR, AGENTS_DIR, BIN_DIR, BACKUPS_DIR, COSTS_DIR, HEARTBEATS_DIR, TRAEFIK_DIR, TRAEFIK_DYNAMIC_DIR, TRAEFIK_CERTS_DIR, CERTS_DIR, CONFIG_FILE, SETTINGS_FILE, CLAUDE_DIR, CODEX_DIR, CURSOR_DIR, GEMINI_DIR, OPENCODE_DIR, SYNC_TARGETS, TEMPLATES_DIR, CLAUDE_MD_TEMPLATES, currentFile, currentDir, packageRoot, SOURCE_TEMPLATES_DIR, SOURCE_TRAEFIK_TEMPLATES, SOURCE_SCRIPTS_DIR, SOURCE_SKILLS_DIR, SOURCE_DEV_SKILLS_DIR, INIT_DIRS;
22
+ var PANOPTICON_HOME, CONFIG_DIR, SKILLS_DIR, COMMANDS_DIR, AGENTS_DIR, BIN_DIR, BACKUPS_DIR, COSTS_DIR, HEARTBEATS_DIR, ARCHIVES_DIR, TRAEFIK_DIR, TRAEFIK_DYNAMIC_DIR, TRAEFIK_CERTS_DIR, CERTS_DIR, CONFIG_FILE, SETTINGS_FILE, CLAUDE_DIR, LEGACY_RUNTIME_DIRS, SYNC_TARGET, TEMPLATES_DIR, CLAUDE_MD_TEMPLATES, currentFile, currentDir, packageRoot, SOURCE_TEMPLATES_DIR, SOURCE_TRAEFIK_TEMPLATES, SOURCE_SCRIPTS_DIR, SOURCE_SKILLS_DIR, SOURCE_DEV_SKILLS_DIR, SOURCE_AGENTS_DIR, SOURCE_RULES_DIR, CACHE_SKILLS_DIR, CACHE_AGENTS_DIR, CACHE_RULES_DIR, CACHE_MANIFEST, DOCS_DIR, PRDS_DIR, PRD_DRAFTS_DIR, PRD_PUBLISHED_DIR, PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR, PROJECT_PRDS_ACTIVE_SUBDIR, PROJECT_PRDS_PLANNED_SUBDIR, PROJECT_PRDS_COMPLETED_SUBDIR, INIT_DIRS;
23
23
  var init_paths = __esm({
24
24
  "src/lib/paths.ts"() {
25
25
  "use strict";
@@ -33,6 +33,7 @@ var init_paths = __esm({
33
33
  BACKUPS_DIR = join(PANOPTICON_HOME, "backups");
34
34
  COSTS_DIR = join(PANOPTICON_HOME, "costs");
35
35
  HEARTBEATS_DIR = join(PANOPTICON_HOME, "heartbeats");
36
+ ARCHIVES_DIR = join(PANOPTICON_HOME, "archives");
36
37
  TRAEFIK_DIR = join(PANOPTICON_HOME, "traefik");
37
38
  TRAEFIK_DYNAMIC_DIR = join(TRAEFIK_DIR, "dynamic");
38
39
  TRAEFIK_CERTS_DIR = join(TRAEFIK_DIR, "certs");
@@ -40,36 +41,16 @@ var init_paths = __esm({
40
41
  CONFIG_FILE = join(CONFIG_DIR, "config.toml");
41
42
  SETTINGS_FILE = join(CONFIG_DIR, "settings.json");
42
43
  CLAUDE_DIR = join(homedir(), ".claude");
43
- CODEX_DIR = join(homedir(), ".codex");
44
- CURSOR_DIR = join(homedir(), ".cursor");
45
- GEMINI_DIR = join(homedir(), ".gemini");
46
- OPENCODE_DIR = join(homedir(), ".opencode");
47
- SYNC_TARGETS = {
48
- claude: {
49
- skills: join(CLAUDE_DIR, "skills"),
50
- commands: join(CLAUDE_DIR, "commands"),
51
- agents: join(CLAUDE_DIR, "agents")
52
- },
53
- codex: {
54
- skills: join(CODEX_DIR, "skills"),
55
- commands: join(CODEX_DIR, "commands"),
56
- agents: join(CODEX_DIR, "agents")
57
- },
58
- cursor: {
59
- skills: join(CURSOR_DIR, "skills"),
60
- commands: join(CURSOR_DIR, "commands"),
61
- agents: join(CURSOR_DIR, "agents")
62
- },
63
- gemini: {
64
- skills: join(GEMINI_DIR, "skills"),
65
- commands: join(GEMINI_DIR, "commands"),
66
- agents: join(GEMINI_DIR, "agents")
67
- },
68
- opencode: {
69
- skills: join(OPENCODE_DIR, "skills"),
70
- commands: join(OPENCODE_DIR, "commands"),
71
- agents: join(OPENCODE_DIR, "agents")
72
- }
44
+ LEGACY_RUNTIME_DIRS = {
45
+ codex: join(homedir(), ".codex"),
46
+ cursor: join(homedir(), ".cursor"),
47
+ gemini: join(homedir(), ".gemini"),
48
+ opencode: join(homedir(), ".opencode")
49
+ };
50
+ SYNC_TARGET = {
51
+ skills: join(CLAUDE_DIR, "skills"),
52
+ commands: join(CLAUDE_DIR, "commands"),
53
+ agents: join(CLAUDE_DIR, "agents")
73
54
  };
74
55
  TEMPLATES_DIR = join(PANOPTICON_HOME, "templates");
75
56
  CLAUDE_MD_TEMPLATES = join(TEMPLATES_DIR, "claude-md", "sections");
@@ -85,6 +66,21 @@ var init_paths = __esm({
85
66
  SOURCE_SCRIPTS_DIR = join(packageRoot, "scripts");
86
67
  SOURCE_SKILLS_DIR = join(packageRoot, "skills");
87
68
  SOURCE_DEV_SKILLS_DIR = join(packageRoot, "dev-skills");
69
+ SOURCE_AGENTS_DIR = join(packageRoot, "agents");
70
+ SOURCE_RULES_DIR = join(packageRoot, "rules");
71
+ CACHE_SKILLS_DIR = SKILLS_DIR;
72
+ CACHE_AGENTS_DIR = join(PANOPTICON_HOME, "agent-definitions");
73
+ CACHE_RULES_DIR = join(PANOPTICON_HOME, "rules");
74
+ CACHE_MANIFEST = join(PANOPTICON_HOME, ".manifest.json");
75
+ DOCS_DIR = join(PANOPTICON_HOME, "docs");
76
+ PRDS_DIR = join(DOCS_DIR, "prds");
77
+ PRD_DRAFTS_DIR = join(PRDS_DIR, "drafts");
78
+ PRD_PUBLISHED_DIR = join(PRDS_DIR, "published");
79
+ PROJECT_DOCS_SUBDIR = "docs";
80
+ PROJECT_PRDS_SUBDIR = "prds";
81
+ PROJECT_PRDS_ACTIVE_SUBDIR = "active";
82
+ PROJECT_PRDS_PLANNED_SUBDIR = "planned";
83
+ PROJECT_PRDS_COMPLETED_SUBDIR = "completed";
88
84
  INIT_DIRS = [
89
85
  PANOPTICON_HOME,
90
86
  SKILLS_DIR,
@@ -97,9 +93,15 @@ var init_paths = __esm({
97
93
  TEMPLATES_DIR,
98
94
  CLAUDE_MD_TEMPLATES,
99
95
  CERTS_DIR,
96
+ CACHE_AGENTS_DIR,
97
+ CACHE_RULES_DIR,
100
98
  TRAEFIK_DIR,
101
99
  TRAEFIK_DYNAMIC_DIR,
102
- TRAEFIK_CERTS_DIR
100
+ TRAEFIK_CERTS_DIR,
101
+ DOCS_DIR,
102
+ PRDS_DIR,
103
+ PRD_DRAFTS_DIR,
104
+ PRD_PUBLISHED_DIR
103
105
  ];
104
106
  }
105
107
  });
@@ -115,6 +117,7 @@ export {
115
117
  BACKUPS_DIR,
116
118
  COSTS_DIR,
117
119
  HEARTBEATS_DIR,
120
+ ARCHIVES_DIR,
118
121
  TRAEFIK_DIR,
119
122
  TRAEFIK_DYNAMIC_DIR,
120
123
  TRAEFIK_CERTS_DIR,
@@ -122,11 +125,8 @@ export {
122
125
  CONFIG_FILE,
123
126
  SETTINGS_FILE,
124
127
  CLAUDE_DIR,
125
- CODEX_DIR,
126
- CURSOR_DIR,
127
- GEMINI_DIR,
128
- OPENCODE_DIR,
129
- SYNC_TARGETS,
128
+ LEGACY_RUNTIME_DIRS,
129
+ SYNC_TARGET,
130
130
  TEMPLATES_DIR,
131
131
  CLAUDE_MD_TEMPLATES,
132
132
  SOURCE_TEMPLATES_DIR,
@@ -134,8 +134,23 @@ export {
134
134
  SOURCE_SCRIPTS_DIR,
135
135
  SOURCE_SKILLS_DIR,
136
136
  SOURCE_DEV_SKILLS_DIR,
137
+ SOURCE_AGENTS_DIR,
138
+ SOURCE_RULES_DIR,
139
+ CACHE_SKILLS_DIR,
140
+ CACHE_AGENTS_DIR,
141
+ CACHE_RULES_DIR,
142
+ CACHE_MANIFEST,
143
+ DOCS_DIR,
144
+ PRDS_DIR,
145
+ PRD_DRAFTS_DIR,
146
+ PRD_PUBLISHED_DIR,
147
+ PROJECT_DOCS_SUBDIR,
148
+ PROJECT_PRDS_SUBDIR,
149
+ PROJECT_PRDS_ACTIVE_SUBDIR,
150
+ PROJECT_PRDS_PLANNED_SUBDIR,
151
+ PROJECT_PRDS_COMPLETED_SUBDIR,
137
152
  isDevMode,
138
153
  INIT_DIRS,
139
154
  init_paths
140
155
  };
141
- //# sourceMappingURL=chunk-6HXKTOD7.js.map
156
+ //# sourceMappingURL=chunk-ZTFNYOC7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/paths.ts"],"sourcesContent":["import { homedir } from 'os';\nimport { join } from 'path';\nimport { existsSync } from 'fs';\n\n// Panopticon home directory (can be overridden for testing)\nexport const PANOPTICON_HOME = process.env.PANOPTICON_HOME || join(homedir(), '.panopticon');\n\n/** Get PANOPTICON_HOME dynamically (reads env var on each call, useful for testing) */\nexport function getPanopticonHome(): string {\n return process.env.PANOPTICON_HOME || join(homedir(), '.panopticon');\n}\n\n// Subdirectories\nexport const CONFIG_DIR = PANOPTICON_HOME;\nexport const SKILLS_DIR = join(PANOPTICON_HOME, 'skills');\nexport const COMMANDS_DIR = join(PANOPTICON_HOME, 'commands');\nexport const AGENTS_DIR = join(PANOPTICON_HOME, 'agents');\nexport const BIN_DIR = join(PANOPTICON_HOME, 'bin');\nexport const BACKUPS_DIR = join(PANOPTICON_HOME, 'backups');\nexport const COSTS_DIR = join(PANOPTICON_HOME, 'costs');\nexport const HEARTBEATS_DIR = join(PANOPTICON_HOME, 'heartbeats');\nexport const ARCHIVES_DIR = join(PANOPTICON_HOME, 'archives');\n\n// Traefik directories\nexport const TRAEFIK_DIR = join(PANOPTICON_HOME, 'traefik');\nexport const TRAEFIK_DYNAMIC_DIR = join(TRAEFIK_DIR, 'dynamic');\nexport const TRAEFIK_CERTS_DIR = join(TRAEFIK_DIR, 'certs');\n\n// Legacy certs directory (for backwards compatibility)\nexport const CERTS_DIR = join(PANOPTICON_HOME, 'certs');\n\n// Config files\nexport const CONFIG_FILE = join(CONFIG_DIR, 'config.toml');\nexport const SETTINGS_FILE = join(CONFIG_DIR, 'settings.json');\n\n// AI tool directory (Claude Code is the sole supported runtime)\nexport const CLAUDE_DIR = join(homedir(), '.claude');\n\n// Legacy runtime directories (kept for symlink cleanup migration)\nexport const LEGACY_RUNTIME_DIRS = {\n codex: join(homedir(), '.codex'),\n cursor: join(homedir(), '.cursor'),\n gemini: join(homedir(), '.gemini'),\n opencode: join(homedir(), '.opencode'),\n} as const;\n\n// Sync target (Claude Code only)\nexport const SYNC_TARGET = {\n skills: join(CLAUDE_DIR, 'skills'),\n commands: join(CLAUDE_DIR, 'commands'),\n agents: join(CLAUDE_DIR, 'agents'),\n} as const;\n\n// Templates directory (in user's ~/.panopticon)\nexport const TEMPLATES_DIR = join(PANOPTICON_HOME, 'templates');\nexport const CLAUDE_MD_TEMPLATES = join(TEMPLATES_DIR, 'claude-md', 'sections');\n\n// Source templates directory (bundled with the package)\n// This is resolved at runtime from the package root\nimport { fileURLToPath } from 'url';\nimport { dirname } from 'path';\n\nconst currentFile = fileURLToPath(import.meta.url);\nconst currentDir = dirname(currentFile);\n\n// Handle both development (src/lib/) and production (dist/) modes\n// In dev: /path/to/panopticon/src/lib/paths.ts -> /path/to/panopticon\n// In prod: /path/to/panopticon/dist/lib/paths.js -> /path/to/panopticon\nlet packageRoot: string;\nif (currentDir.includes('/src/')) {\n // Development mode - go up from src/lib to package root\n packageRoot = dirname(dirname(currentDir));\n} else {\n // Production mode - go up from dist (or dist/lib) to package root\n packageRoot = currentDir.endsWith('/lib')\n ? dirname(dirname(currentDir))\n : dirname(currentDir);\n}\n\nexport const SOURCE_TEMPLATES_DIR = join(packageRoot, 'templates');\nexport const SOURCE_TRAEFIK_TEMPLATES = join(SOURCE_TEMPLATES_DIR, 'traefik');\nexport const SOURCE_SCRIPTS_DIR = join(packageRoot, 'scripts');\nexport const SOURCE_SKILLS_DIR = join(packageRoot, 'skills');\nexport const SOURCE_DEV_SKILLS_DIR = join(packageRoot, 'dev-skills');\nexport const SOURCE_AGENTS_DIR = join(packageRoot, 'agents');\nexport const SOURCE_RULES_DIR = join(packageRoot, 'rules');\n\n// Cache directories (where Panopticon keeps its copy of distributed content)\nexport const CACHE_SKILLS_DIR = SKILLS_DIR; // ~/.panopticon/skills/\nexport const CACHE_AGENTS_DIR = join(PANOPTICON_HOME, 'agent-definitions'); // separate from agent state\nexport const CACHE_RULES_DIR = join(PANOPTICON_HOME, 'rules');\nexport const CACHE_MANIFEST = join(PANOPTICON_HOME, '.manifest.json');\n\n// Pre-workspace PRD directory (for PRDs created before workspace exists)\nexport const DOCS_DIR = join(PANOPTICON_HOME, 'docs');\nexport const PRDS_DIR = join(DOCS_DIR, 'prds');\nexport const PRD_DRAFTS_DIR = join(PRDS_DIR, 'drafts');\nexport const PRD_PUBLISHED_DIR = join(PRDS_DIR, 'published');\n\n// Project-relative docs paths (subdirectory names for project-level docs)\nexport const PROJECT_DOCS_SUBDIR = 'docs';\nexport const PROJECT_PRDS_SUBDIR = 'prds';\nexport const PROJECT_PRDS_ACTIVE_SUBDIR = 'active';\nexport const PROJECT_PRDS_PLANNED_SUBDIR = 'planned';\nexport const PROJECT_PRDS_COMPLETED_SUBDIR = 'completed';\n\n/**\n * Detect if running in development mode (from npm link or panopticon repo)\n *\n * Dev mode is detected if:\n * 1. Running from the panopticon source directory (npm link)\n * 2. The SOURCE_DEV_SKILLS_DIR exists (only present in repo, not in npm package)\n */\nexport function isDevMode(): boolean {\n try {\n // Check if dev-skills directory exists - this is only in the repo, not npm package\n return existsSync(SOURCE_DEV_SKILLS_DIR);\n } catch {\n return false;\n }\n}\n\n// All directories to create on init\nexport const INIT_DIRS = [\n PANOPTICON_HOME,\n SKILLS_DIR,\n COMMANDS_DIR,\n AGENTS_DIR,\n BIN_DIR,\n BACKUPS_DIR,\n COSTS_DIR,\n HEARTBEATS_DIR,\n TEMPLATES_DIR,\n CLAUDE_MD_TEMPLATES,\n CERTS_DIR,\n CACHE_AGENTS_DIR,\n CACHE_RULES_DIR,\n TRAEFIK_DIR,\n TRAEFIK_DYNAMIC_DIR,\n TRAEFIK_CERTS_DIR,\n DOCS_DIR,\n PRDS_DIR,\n PRD_DRAFTS_DIR,\n PRD_PUBLISHED_DIR,\n];\n"],"mappings":"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","names":[]}