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,677 @@
1
+ import {
2
+ buildManifestFromDirectory,
3
+ collectSourceFiles,
4
+ compareFileToManifest,
5
+ hashFile,
6
+ init_manifest,
7
+ readManifest,
8
+ setManifestEntry,
9
+ writeManifest
10
+ } from "./chunk-AQXETQHW.js";
11
+ import {
12
+ init_factory,
13
+ init_github,
14
+ init_gitlab,
15
+ init_linear
16
+ } from "./chunk-XFR2DLMR.js";
17
+ import {
18
+ getDevrootPath,
19
+ init_config
20
+ } from "./chunk-FQ66DECN.js";
21
+ import {
22
+ init_interface
23
+ } from "./chunk-CFCUOV3Q.js";
24
+ import {
25
+ BACKUPS_DIR,
26
+ BIN_DIR,
27
+ CACHE_AGENTS_DIR,
28
+ CACHE_MANIFEST,
29
+ CACHE_RULES_DIR,
30
+ SKILLS_DIR,
31
+ SOURCE_AGENTS_DIR,
32
+ SOURCE_DEV_SKILLS_DIR,
33
+ SOURCE_RULES_DIR,
34
+ SOURCE_SCRIPTS_DIR,
35
+ SOURCE_SKILLS_DIR,
36
+ init_paths,
37
+ isDevMode
38
+ } from "./chunk-ZTFNYOC7.js";
39
+ import {
40
+ init_esm_shims
41
+ } from "./chunk-ZHC57RCV.js";
42
+
43
+ // src/lib/shell.ts
44
+ init_esm_shims();
45
+ import { existsSync, readFileSync, appendFileSync } from "fs";
46
+ import { homedir } from "os";
47
+ import { join } from "path";
48
+ function detectShell() {
49
+ const shell = process.env.SHELL || "";
50
+ if (shell.includes("zsh")) return "zsh";
51
+ if (shell.includes("bash")) return "bash";
52
+ if (shell.includes("fish")) return "fish";
53
+ return "unknown";
54
+ }
55
+ function getShellRcFile(shell) {
56
+ const home = homedir();
57
+ switch (shell) {
58
+ case "zsh":
59
+ return join(home, ".zshrc");
60
+ case "bash":
61
+ const bashrc = join(home, ".bashrc");
62
+ if (existsSync(bashrc)) return bashrc;
63
+ return join(home, ".bash_profile");
64
+ case "fish":
65
+ return join(home, ".config", "fish", "config.fish");
66
+ default:
67
+ return null;
68
+ }
69
+ }
70
+ var ALIAS_LINE = 'alias pan="panopticon"';
71
+ var ALIAS_MARKER = "# Panopticon CLI alias";
72
+ function hasAlias(rcFile) {
73
+ if (!existsSync(rcFile)) return false;
74
+ const content = readFileSync(rcFile, "utf8");
75
+ return content.includes(ALIAS_MARKER) || content.includes(ALIAS_LINE);
76
+ }
77
+ function addAlias(rcFile) {
78
+ if (hasAlias(rcFile)) return;
79
+ const aliasBlock = `
80
+ ${ALIAS_MARKER}
81
+ ${ALIAS_LINE}
82
+ `;
83
+ appendFileSync(rcFile, aliasBlock, "utf8");
84
+ }
85
+ function getAliasInstructions(shell) {
86
+ const rcFile = getShellRcFile(shell);
87
+ if (!rcFile) {
88
+ return `Add this to your shell config:
89
+ ${ALIAS_LINE}`;
90
+ }
91
+ return `Alias added to ${rcFile}. Run:
92
+ source ${rcFile}`;
93
+ }
94
+
95
+ // src/lib/backup.ts
96
+ init_esm_shims();
97
+ init_paths();
98
+ import { existsSync as existsSync2, mkdirSync, readdirSync, cpSync, rmSync, lstatSync } from "fs";
99
+ import { join as join2, basename } from "path";
100
+ function createBackupTimestamp() {
101
+ return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
102
+ }
103
+ function createBackup(sourceDirs) {
104
+ const timestamp = createBackupTimestamp();
105
+ const backupPath = join2(BACKUPS_DIR, timestamp);
106
+ mkdirSync(backupPath, { recursive: true });
107
+ const targets = [];
108
+ for (const sourceDir of sourceDirs) {
109
+ if (!existsSync2(sourceDir)) continue;
110
+ const targetName = basename(sourceDir);
111
+ const targetPath = join2(backupPath, targetName);
112
+ cpSync(sourceDir, targetPath, {
113
+ recursive: true,
114
+ filter: (src) => !lstatSync(src).isSymbolicLink()
115
+ });
116
+ targets.push(targetName);
117
+ }
118
+ return {
119
+ timestamp,
120
+ path: backupPath,
121
+ targets
122
+ };
123
+ }
124
+ function listBackups() {
125
+ if (!existsSync2(BACKUPS_DIR)) return [];
126
+ const entries = readdirSync(BACKUPS_DIR, { withFileTypes: true });
127
+ return entries.filter((e) => e.isDirectory()).map((e) => {
128
+ const backupPath = join2(BACKUPS_DIR, e.name);
129
+ const contents = readdirSync(backupPath);
130
+ return {
131
+ timestamp: e.name,
132
+ path: backupPath,
133
+ targets: contents
134
+ };
135
+ }).sort((a, b) => b.timestamp.localeCompare(a.timestamp));
136
+ }
137
+ function restoreBackup(timestamp, targetDirs) {
138
+ const backupPath = join2(BACKUPS_DIR, timestamp);
139
+ if (!existsSync2(backupPath)) {
140
+ throw new Error(`Backup not found: ${timestamp}`);
141
+ }
142
+ const contents = readdirSync(backupPath, { withFileTypes: true });
143
+ for (const entry of contents) {
144
+ if (!entry.isDirectory()) continue;
145
+ const sourcePath = join2(backupPath, entry.name);
146
+ const targetPath = targetDirs[entry.name];
147
+ if (!targetPath) continue;
148
+ if (existsSync2(targetPath)) {
149
+ rmSync(targetPath, { recursive: true });
150
+ }
151
+ cpSync(sourcePath, targetPath, { recursive: true });
152
+ }
153
+ }
154
+ function cleanOldBackups(keepCount = 10) {
155
+ const backups = listBackups();
156
+ if (backups.length <= keepCount) return 0;
157
+ const toRemove = backups.slice(keepCount);
158
+ let removed = 0;
159
+ for (const backup of toRemove) {
160
+ rmSync(backup.path, { recursive: true });
161
+ removed++;
162
+ }
163
+ return removed;
164
+ }
165
+
166
+ // src/lib/sync.ts
167
+ init_esm_shims();
168
+ init_paths();
169
+ init_manifest();
170
+ init_config();
171
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync2, unlinkSync, lstatSync as lstatSync2, readlinkSync, rmSync as rmSync2, copyFileSync, chmodSync, readFileSync as readFileSync2, writeFileSync } from "fs";
172
+ import { join as join3, dirname } from "path";
173
+ import { homedir as homedir2 } from "os";
174
+ function isPanopticonSymlink(targetPath) {
175
+ if (!existsSync3(targetPath)) return false;
176
+ try {
177
+ const stats = lstatSync2(targetPath);
178
+ if (!stats.isSymbolicLink()) return false;
179
+ const linkTarget = readlinkSync(targetPath);
180
+ return linkTarget.includes(".panopticon");
181
+ } catch {
182
+ return false;
183
+ }
184
+ }
185
+ function migrateFromPersonalSymlinks() {
186
+ const claudeDir = join3(homedir2(), ".claude");
187
+ const result = {
188
+ removedSymlinks: [],
189
+ preservedUserContent: [],
190
+ errors: []
191
+ };
192
+ for (const subdir of ["skills", "commands", "agents"]) {
193
+ const dir = join3(claudeDir, subdir);
194
+ if (!existsSync3(dir)) continue;
195
+ try {
196
+ const entries = readdirSync2(dir);
197
+ for (const entry of entries) {
198
+ const entryPath = join3(dir, entry);
199
+ try {
200
+ const stats = lstatSync2(entryPath);
201
+ if (stats.isSymbolicLink()) {
202
+ const linkTarget = readlinkSync(entryPath);
203
+ if (linkTarget.includes(".panopticon") || linkTarget.includes("panopticon-cli")) {
204
+ unlinkSync(entryPath);
205
+ result.removedSymlinks.push(`${subdir}/${entry}`);
206
+ } else {
207
+ result.preservedUserContent.push(`${subdir}/${entry}`);
208
+ }
209
+ } else {
210
+ result.preservedUserContent.push(`${subdir}/${entry}`);
211
+ }
212
+ } catch (err) {
213
+ result.errors.push(`${subdir}/${entry}: ${err.message}`);
214
+ }
215
+ }
216
+ } catch (err) {
217
+ result.errors.push(`${subdir}: ${err.message}`);
218
+ }
219
+ }
220
+ return result;
221
+ }
222
+ function copyDirectoryRecursive(source, dest) {
223
+ if (!existsSync3(source)) return 0;
224
+ mkdirSync2(dest, { recursive: true });
225
+ let count = 0;
226
+ const entries = readdirSync2(source, { withFileTypes: true });
227
+ for (const entry of entries) {
228
+ const srcPath = join3(source, entry.name);
229
+ const dstPath = join3(dest, entry.name);
230
+ if (entry.isDirectory()) {
231
+ count += copyDirectoryRecursive(srcPath, dstPath);
232
+ } else if (entry.isFile()) {
233
+ copyFileSync(srcPath, dstPath);
234
+ count++;
235
+ }
236
+ }
237
+ return count;
238
+ }
239
+ function refreshCache() {
240
+ const result = {
241
+ skills: { copied: 0, total: 0 },
242
+ agents: { copied: 0, total: 0 },
243
+ rules: { copied: 0, total: 0 }
244
+ };
245
+ if (existsSync3(SOURCE_SKILLS_DIR)) {
246
+ const skillDirs = readdirSync2(SOURCE_SKILLS_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
247
+ result.skills.total = skillDirs.length;
248
+ for (const skillDir of skillDirs) {
249
+ const src = join3(SOURCE_SKILLS_DIR, skillDir.name);
250
+ const dst = join3(SKILLS_DIR, skillDir.name);
251
+ copyDirectoryRecursive(src, dst);
252
+ result.skills.copied++;
253
+ }
254
+ }
255
+ if (isDevMode() && existsSync3(SOURCE_DEV_SKILLS_DIR)) {
256
+ const devSkillDirs = readdirSync2(SOURCE_DEV_SKILLS_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
257
+ for (const skillDir of devSkillDirs) {
258
+ const src = join3(SOURCE_DEV_SKILLS_DIR, skillDir.name);
259
+ const dst = join3(SKILLS_DIR, skillDir.name);
260
+ copyDirectoryRecursive(src, dst);
261
+ result.skills.copied++;
262
+ result.skills.total++;
263
+ }
264
+ }
265
+ if (existsSync3(SOURCE_AGENTS_DIR)) {
266
+ mkdirSync2(CACHE_AGENTS_DIR, { recursive: true });
267
+ const agents = readdirSync2(SOURCE_AGENTS_DIR, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md"));
268
+ result.agents.total = agents.length;
269
+ for (const agent of agents) {
270
+ copyFileSync(join3(SOURCE_AGENTS_DIR, agent.name), join3(CACHE_AGENTS_DIR, agent.name));
271
+ result.agents.copied++;
272
+ }
273
+ }
274
+ if (existsSync3(SOURCE_RULES_DIR)) {
275
+ const ruleFiles = readdirSync2(SOURCE_RULES_DIR, { withFileTypes: true }).filter((entry) => entry.isFile());
276
+ result.rules.total = ruleFiles.length;
277
+ for (const rule of ruleFiles) {
278
+ mkdirSync2(CACHE_RULES_DIR, { recursive: true });
279
+ copyFileSync(join3(SOURCE_RULES_DIR, rule.name), join3(CACHE_RULES_DIR, rule.name));
280
+ result.rules.copied++;
281
+ }
282
+ }
283
+ const manifest = buildManifestFromDirectory(
284
+ join3(SKILLS_DIR, ".."),
285
+ // ~/.panopticon/
286
+ ["skills", "agent-definitions", "rules"],
287
+ "panopticon"
288
+ );
289
+ writeManifest(CACHE_MANIFEST, manifest);
290
+ return result;
291
+ }
292
+ function planSync() {
293
+ const plan = {
294
+ skills: [],
295
+ commands: [],
296
+ agents: [],
297
+ rules: [],
298
+ devSkills: []
299
+ };
300
+ const devrootPath = getDevrootPath();
301
+ if (!devrootPath) return plan;
302
+ const targetBase = join3(devrootPath, ".claude");
303
+ const manifestPath = join3(targetBase, ".panopticon-manifest.json");
304
+ const manifest = readManifest(manifestPath);
305
+ const skillFiles = collectSourceFiles(SKILLS_DIR, "skills/");
306
+ for (const file of skillFiles) {
307
+ const targetFile = join3(targetBase, file.relativePath);
308
+ const status = compareFileToManifest(targetFile, file.relativePath, manifest);
309
+ const skillName = file.relativePath.split("/")[1] || file.relativePath;
310
+ let syncStatus = "new";
311
+ if (status.action === "update") syncStatus = "symlink";
312
+ else if (status.action === "modified") syncStatus = "conflict";
313
+ else if (status.action === "user-owned") syncStatus = "conflict";
314
+ plan.skills.push({
315
+ name: file.relativePath,
316
+ sourcePath: file.absolutePath,
317
+ targetPath: targetFile,
318
+ status: syncStatus
319
+ });
320
+ }
321
+ const agentFiles = collectSourceFiles(CACHE_AGENTS_DIR, "agents/");
322
+ for (const file of agentFiles) {
323
+ const targetFile = join3(targetBase, file.relativePath);
324
+ const status = compareFileToManifest(targetFile, file.relativePath, manifest);
325
+ let syncStatus = "new";
326
+ if (status.action === "update") syncStatus = "symlink";
327
+ else if (status.action === "modified") syncStatus = "conflict";
328
+ else if (status.action === "user-owned") syncStatus = "conflict";
329
+ plan.agents.push({
330
+ name: file.relativePath,
331
+ sourcePath: file.absolutePath,
332
+ targetPath: targetFile,
333
+ status: syncStatus
334
+ });
335
+ }
336
+ const ruleFiles = collectSourceFiles(CACHE_RULES_DIR, "rules/");
337
+ for (const file of ruleFiles) {
338
+ const targetFile = join3(targetBase, file.relativePath);
339
+ const status = compareFileToManifest(targetFile, file.relativePath, manifest);
340
+ let syncStatus = "new";
341
+ if (status.action === "update") syncStatus = "symlink";
342
+ else if (status.action === "modified") syncStatus = "conflict";
343
+ else if (status.action === "user-owned") syncStatus = "conflict";
344
+ plan.rules.push({
345
+ name: file.relativePath,
346
+ sourcePath: file.absolutePath,
347
+ targetPath: targetFile,
348
+ status: syncStatus
349
+ });
350
+ }
351
+ return plan;
352
+ }
353
+ function executeSync(options = {}) {
354
+ const result = {
355
+ created: [],
356
+ updated: [],
357
+ skipped: [],
358
+ conflicts: [],
359
+ diffs: []
360
+ };
361
+ const devrootPath = getDevrootPath();
362
+ if (!devrootPath) {
363
+ return result;
364
+ }
365
+ const targetBase = join3(devrootPath, ".claude");
366
+ const manifestPath = join3(targetBase, ".panopticon-manifest.json");
367
+ const manifest = readManifest(manifestPath);
368
+ const allFiles = [
369
+ ...collectSourceFiles(SKILLS_DIR, "skills/"),
370
+ ...collectSourceFiles(CACHE_AGENTS_DIR, "agents/"),
371
+ ...collectSourceFiles(CACHE_RULES_DIR, "rules/")
372
+ ];
373
+ for (const file of allFiles) {
374
+ const targetFile = join3(targetBase, file.relativePath);
375
+ const status = compareFileToManifest(targetFile, file.relativePath, manifest);
376
+ switch (status.action) {
377
+ case "new": {
378
+ mkdirSync2(dirname(targetFile), { recursive: true });
379
+ copyFileSync(file.absolutePath, targetFile);
380
+ const hash = hashFile(targetFile);
381
+ setManifestEntry(manifest, file.relativePath, hash, "panopticon");
382
+ result.created.push(file.relativePath);
383
+ break;
384
+ }
385
+ case "update": {
386
+ mkdirSync2(dirname(targetFile), { recursive: true });
387
+ copyFileSync(file.absolutePath, targetFile);
388
+ const hash = hashFile(targetFile);
389
+ setManifestEntry(manifest, file.relativePath, hash, "panopticon");
390
+ result.updated.push(file.relativePath);
391
+ break;
392
+ }
393
+ case "modified": {
394
+ if (options.diff) {
395
+ result.diffs.push({
396
+ path: file.relativePath,
397
+ sourceContent: readFileSync2(file.absolutePath, "utf-8"),
398
+ targetContent: readFileSync2(targetFile, "utf-8")
399
+ });
400
+ }
401
+ if (options.force) {
402
+ mkdirSync2(dirname(targetFile), { recursive: true });
403
+ copyFileSync(file.absolutePath, targetFile);
404
+ const hash = hashFile(targetFile);
405
+ setManifestEntry(manifest, file.relativePath, hash, "panopticon");
406
+ result.updated.push(file.relativePath);
407
+ } else {
408
+ result.conflicts.push(file.relativePath);
409
+ }
410
+ break;
411
+ }
412
+ case "user-owned": {
413
+ result.skipped.push(file.relativePath);
414
+ break;
415
+ }
416
+ }
417
+ }
418
+ writeManifest(manifestPath, manifest);
419
+ return result;
420
+ }
421
+ function planHooksSync() {
422
+ const hooks = [];
423
+ if (!existsSync3(SOURCE_SCRIPTS_DIR)) {
424
+ return hooks;
425
+ }
426
+ const scripts = readdirSync2(SOURCE_SCRIPTS_DIR, { withFileTypes: true }).filter((entry) => entry.isFile() && !entry.name.startsWith(".") && (!entry.name.includes(".") || entry.name.endsWith(".js")));
427
+ for (const script of scripts) {
428
+ const sourcePath = join3(SOURCE_SCRIPTS_DIR, script.name);
429
+ const targetPath = join3(BIN_DIR, script.name);
430
+ let status = "new";
431
+ if (existsSync3(targetPath)) {
432
+ status = "updated";
433
+ }
434
+ hooks.push({ name: script.name, sourcePath, targetPath, status });
435
+ }
436
+ return hooks;
437
+ }
438
+ function syncHooks() {
439
+ const result = { synced: [], errors: [] };
440
+ mkdirSync2(BIN_DIR, { recursive: true });
441
+ const hooks = planHooksSync();
442
+ for (const hook of hooks) {
443
+ try {
444
+ copyFileSync(hook.sourcePath, hook.targetPath);
445
+ chmodSync(hook.targetPath, 493);
446
+ result.synced.push(hook.name);
447
+ } catch (error) {
448
+ result.errors.push(`${hook.name}: ${error}`);
449
+ }
450
+ }
451
+ return result;
452
+ }
453
+ var STATUSLINE_TARGETS = {
454
+ claude: {
455
+ configDir: join3(homedir2(), ".claude"),
456
+ scriptName: "statusline-command.sh",
457
+ settingsFile: join3(homedir2(), ".claude", "settings.json")
458
+ }
459
+ // Other runtimes can be added as they support statusline
460
+ };
461
+ function syncStatusline() {
462
+ const result = { synced: [], errors: [] };
463
+ const sourceScript = join3(SOURCE_SCRIPTS_DIR, "statusline.sh");
464
+ if (!existsSync3(sourceScript)) {
465
+ return result;
466
+ }
467
+ for (const [runtime, target] of Object.entries(STATUSLINE_TARGETS)) {
468
+ try {
469
+ mkdirSync2(target.configDir, { recursive: true });
470
+ const targetScript = join3(target.configDir, target.scriptName);
471
+ copyFileSync(sourceScript, targetScript);
472
+ chmodSync(targetScript, 493);
473
+ updateSettingsStatusline(target.settingsFile, targetScript);
474
+ result.synced.push(runtime);
475
+ } catch (error) {
476
+ result.errors.push(`${runtime}: ${error}`);
477
+ }
478
+ }
479
+ return result;
480
+ }
481
+ function updateSettingsStatusline(settingsFile, scriptPath) {
482
+ let settings = {};
483
+ if (existsSync3(settingsFile)) {
484
+ try {
485
+ settings = JSON.parse(readFileSync2(settingsFile, "utf-8"));
486
+ } catch {
487
+ settings = {};
488
+ }
489
+ }
490
+ const currentCommand = settings.statusLine?.command;
491
+ if (currentCommand === scriptPath && settings.statusLine?.type === "command") {
492
+ return;
493
+ }
494
+ settings.statusLine = {
495
+ type: "command",
496
+ command: scriptPath,
497
+ padding: 0
498
+ };
499
+ mkdirSync2(dirname(settingsFile), { recursive: true });
500
+ writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + "\n", "utf-8");
501
+ }
502
+
503
+ // src/lib/tracker/linking.ts
504
+ init_esm_shims();
505
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
506
+ import { join as join4 } from "path";
507
+ import { homedir as homedir3 } from "os";
508
+ function parseIssueRef(ref) {
509
+ if (ref.startsWith("github#")) {
510
+ return { tracker: "github", ref: `#${ref.slice(7)}` };
511
+ }
512
+ if (ref.startsWith("gitlab#")) {
513
+ return { tracker: "gitlab", ref: `#${ref.slice(7)}` };
514
+ }
515
+ if (ref.startsWith("linear:")) {
516
+ return { tracker: "linear", ref: ref.slice(7) };
517
+ }
518
+ if (/^#\d+$/.test(ref)) {
519
+ return { tracker: "github", ref };
520
+ }
521
+ if (/^[A-Z]+-\d+$/i.test(ref)) {
522
+ return { tracker: "linear", ref: ref.toUpperCase() };
523
+ }
524
+ return null;
525
+ }
526
+ function formatIssueRef(ref, tracker) {
527
+ if (tracker === "github") {
528
+ return ref.startsWith("#") ? `github${ref}` : `github#${ref}`;
529
+ }
530
+ if (tracker === "gitlab") {
531
+ return ref.startsWith("#") ? `gitlab${ref}` : `gitlab#${ref}`;
532
+ }
533
+ return ref;
534
+ }
535
+ var LinkManager = class {
536
+ storePath;
537
+ store;
538
+ constructor(storePath) {
539
+ this.storePath = storePath ?? join4(homedir3(), ".panopticon", "links.json");
540
+ this.store = this.load();
541
+ }
542
+ load() {
543
+ if (existsSync4(this.storePath)) {
544
+ try {
545
+ const data = JSON.parse(readFileSync3(this.storePath, "utf-8"));
546
+ if (data.version === 1) {
547
+ return data;
548
+ }
549
+ } catch {
550
+ }
551
+ }
552
+ return { version: 1, links: [] };
553
+ }
554
+ save() {
555
+ const dir = join4(this.storePath, "..");
556
+ if (!existsSync4(dir)) {
557
+ mkdirSync3(dir, { recursive: true });
558
+ }
559
+ writeFileSync2(this.storePath, JSON.stringify(this.store, null, 2));
560
+ }
561
+ /**
562
+ * Add a link between two issues
563
+ */
564
+ addLink(source, target, direction = "related") {
565
+ const existing = this.store.links.find(
566
+ (l) => l.sourceIssueRef === source.ref && l.sourceTracker === source.tracker && l.targetIssueRef === target.ref && l.targetTracker === target.tracker
567
+ );
568
+ if (existing) {
569
+ if (existing.direction !== direction) {
570
+ existing.direction = direction;
571
+ this.save();
572
+ }
573
+ return existing;
574
+ }
575
+ const link = {
576
+ sourceIssueRef: source.ref,
577
+ sourceTracker: source.tracker,
578
+ targetIssueRef: target.ref,
579
+ targetTracker: target.tracker,
580
+ direction,
581
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
582
+ };
583
+ this.store.links.push(link);
584
+ this.save();
585
+ return link;
586
+ }
587
+ /**
588
+ * Remove a link between two issues
589
+ */
590
+ removeLink(source, target) {
591
+ const index = this.store.links.findIndex(
592
+ (l) => l.sourceIssueRef === source.ref && l.sourceTracker === source.tracker && l.targetIssueRef === target.ref && l.targetTracker === target.tracker
593
+ );
594
+ if (index >= 0) {
595
+ this.store.links.splice(index, 1);
596
+ this.save();
597
+ return true;
598
+ }
599
+ return false;
600
+ }
601
+ /**
602
+ * Get all issues linked to a given issue
603
+ */
604
+ getLinkedIssues(ref, tracker) {
605
+ return this.store.links.filter(
606
+ (l) => l.sourceIssueRef === ref && l.sourceTracker === tracker || l.targetIssueRef === ref && l.targetTracker === tracker
607
+ );
608
+ }
609
+ /**
610
+ * Get all links (for debugging/admin)
611
+ */
612
+ getAllLinks() {
613
+ return [...this.store.links];
614
+ }
615
+ /**
616
+ * Find linked issue in another tracker
617
+ */
618
+ findLinkedIssue(ref, sourceTracker, targetTracker) {
619
+ const asSource = this.store.links.find(
620
+ (l) => l.sourceIssueRef === ref && l.sourceTracker === sourceTracker && l.targetTracker === targetTracker
621
+ );
622
+ if (asSource) return asSource.targetIssueRef;
623
+ const asTarget = this.store.links.find(
624
+ (l) => l.targetIssueRef === ref && l.targetTracker === sourceTracker && l.sourceTracker === targetTracker
625
+ );
626
+ if (asTarget) return asTarget.sourceIssueRef;
627
+ return null;
628
+ }
629
+ /**
630
+ * Clear all links (for testing)
631
+ */
632
+ clear() {
633
+ this.store.links = [];
634
+ this.save();
635
+ }
636
+ };
637
+ var _linkManager = null;
638
+ function getLinkManager() {
639
+ if (!_linkManager) {
640
+ _linkManager = new LinkManager();
641
+ }
642
+ return _linkManager;
643
+ }
644
+
645
+ // src/lib/tracker/index.ts
646
+ init_esm_shims();
647
+ init_interface();
648
+ init_linear();
649
+ init_github();
650
+ init_gitlab();
651
+ init_factory();
652
+
653
+ export {
654
+ detectShell,
655
+ getShellRcFile,
656
+ hasAlias,
657
+ addAlias,
658
+ getAliasInstructions,
659
+ createBackupTimestamp,
660
+ createBackup,
661
+ listBackups,
662
+ restoreBackup,
663
+ cleanOldBackups,
664
+ isPanopticonSymlink,
665
+ migrateFromPersonalSymlinks,
666
+ refreshCache,
667
+ planSync,
668
+ executeSync,
669
+ planHooksSync,
670
+ syncHooks,
671
+ syncStatusline,
672
+ parseIssueRef,
673
+ formatIssueRef,
674
+ LinkManager,
675
+ getLinkManager
676
+ };
677
+ //# sourceMappingURL=chunk-XKT5MHPT.js.map