panopticon-cli 0.4.32 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -210
- package/dist/{agents-BDFHF4T3.js → agents-E43Y3HNU.js} +10 -7
- package/dist/chunk-7SN4L4PH.js +150 -0
- package/dist/chunk-7SN4L4PH.js.map +1 -0
- package/dist/{chunk-2NIAOCIC.js → chunk-AAFQANKW.js} +358 -97
- package/dist/chunk-AAFQANKW.js.map +1 -0
- package/dist/chunk-AQXETQHW.js +113 -0
- package/dist/chunk-AQXETQHW.js.map +1 -0
- package/dist/chunk-B3PF6JPQ.js +212 -0
- package/dist/chunk-B3PF6JPQ.js.map +1 -0
- package/dist/chunk-CFCUOV3Q.js +669 -0
- package/dist/chunk-CFCUOV3Q.js.map +1 -0
- package/dist/chunk-CWELWPWQ.js +32 -0
- package/dist/chunk-CWELWPWQ.js.map +1 -0
- package/dist/chunk-DI7ABPNQ.js +352 -0
- package/dist/chunk-DI7ABPNQ.js.map +1 -0
- package/dist/{chunk-VU4FLXV5.js → chunk-FQ66DECN.js} +31 -4
- package/dist/chunk-FQ66DECN.js.map +1 -0
- package/dist/{chunk-VIWUCJ4V.js → chunk-FTCPTHIJ.js} +57 -432
- package/dist/chunk-FTCPTHIJ.js.map +1 -0
- package/dist/{review-status-GWQYY77L.js → chunk-GFP3PIPB.js} +14 -7
- package/dist/chunk-GFP3PIPB.js.map +1 -0
- package/dist/chunk-GR6ZZMCX.js +816 -0
- package/dist/chunk-GR6ZZMCX.js.map +1 -0
- package/dist/chunk-HJSM6E6U.js +1038 -0
- package/dist/chunk-HJSM6E6U.js.map +1 -0
- package/dist/{chunk-XP2DXWYP.js → chunk-HZT2AOPN.js} +164 -39
- package/dist/chunk-HZT2AOPN.js.map +1 -0
- package/dist/chunk-JQBV3Q2W.js +29 -0
- package/dist/chunk-JQBV3Q2W.js.map +1 -0
- package/dist/{chunk-BWGFN44T.js → chunk-JT4O4YVM.js} +28 -16
- package/dist/chunk-JT4O4YVM.js.map +1 -0
- package/dist/chunk-NTO3EDB3.js +600 -0
- package/dist/chunk-NTO3EDB3.js.map +1 -0
- package/dist/{chunk-JY7R7V4G.js → chunk-OMNXYPXC.js} +2 -2
- package/dist/chunk-OMNXYPXC.js.map +1 -0
- package/dist/chunk-PELXV435.js +215 -0
- package/dist/chunk-PELXV435.js.map +1 -0
- package/dist/chunk-PPRFKTVC.js +154 -0
- package/dist/chunk-PPRFKTVC.js.map +1 -0
- package/dist/chunk-WQG2TYCB.js +677 -0
- package/dist/chunk-WQG2TYCB.js.map +1 -0
- package/dist/{chunk-HCTJFIJJ.js → chunk-YLPSQAM2.js} +2 -2
- package/dist/{chunk-HCTJFIJJ.js.map → chunk-YLPSQAM2.js.map} +1 -1
- package/dist/{chunk-6HXKTOD7.js → chunk-ZTFNYOC7.js} +53 -38
- package/dist/chunk-ZTFNYOC7.js.map +1 -0
- package/dist/cli/index.js +5103 -3165
- package/dist/cli/index.js.map +1 -1
- package/dist/{config-BOAMSKTF.js → config-4CJNUE3O.js} +7 -3
- package/dist/dashboard/prompts/merge-agent.md +217 -0
- package/dist/dashboard/prompts/review-agent.md +409 -0
- package/dist/dashboard/prompts/sync-main.md +84 -0
- package/dist/dashboard/prompts/test-agent.md +283 -0
- package/dist/dashboard/prompts/work-agent.md +249 -0
- package/dist/dashboard/public/assets/index-BxpjweAL.css +32 -0
- package/dist/dashboard/public/assets/index-DQHkwvvJ.js +743 -0
- package/dist/dashboard/public/index.html +2 -2
- package/dist/dashboard/server.js +17619 -4044
- package/dist/{dns-L3L2BB27.js → dns-7BDJSD3E.js} +4 -2
- package/dist/{feedback-writer-AAKF5BTK.js → feedback-writer-LVZ5TFYZ.js} +8 -4
- package/dist/feedback-writer-LVZ5TFYZ.js.map +1 -0
- package/dist/hume-WMAUBBV2.js +13 -0
- package/dist/index.d.ts +162 -40
- package/dist/index.js +67 -23
- package/dist/index.js.map +1 -1
- package/dist/{projects-VXRUCMLM.js → projects-JEIVIYC6.js} +3 -3
- package/dist/rally-RKFSWC7E.js +10 -0
- package/dist/{remote-agents-Z3R2A5BN.js → remote-agents-TFSMW7GN.js} +2 -2
- package/dist/{remote-workspace-2G6V2KNP.js → remote-workspace-AHVHQEES.js} +8 -8
- package/dist/review-status-EPFG4XM7.js +19 -0
- package/dist/shadow-state-5MDP6YXH.js +30 -0
- package/dist/shadow-state-5MDP6YXH.js.map +1 -0
- package/dist/{specialist-context-N32QBNNQ.js → specialist-context-ZC6A4M3I.js} +8 -7
- package/dist/{specialist-context-N32QBNNQ.js.map → specialist-context-ZC6A4M3I.js.map} +1 -1
- package/dist/{specialist-logs-GF3YV4KL.js → specialist-logs-KLGJCEUL.js} +7 -6
- package/dist/specialist-logs-KLGJCEUL.js.map +1 -0
- package/dist/{specialists-JBIW6MP4.js → specialists-O4HWDJL5.js} +7 -6
- package/dist/specialists-O4HWDJL5.js.map +1 -0
- package/dist/tldr-daemon-T3THOUGT.js +21 -0
- package/dist/tldr-daemon-T3THOUGT.js.map +1 -0
- package/dist/traefik-QN7R5I6V.js +19 -0
- package/dist/traefik-QN7R5I6V.js.map +1 -0
- package/dist/tunnel-W2GZBLEV.js +13 -0
- package/dist/tunnel-W2GZBLEV.js.map +1 -0
- package/dist/workspace-manager-IE4JL2JP.js +22 -0
- package/dist/workspace-manager-IE4JL2JP.js.map +1 -0
- package/package.json +2 -2
- package/scripts/heartbeat-hook +37 -10
- package/scripts/patches/llm-tldr-tsx-support.py +109 -0
- package/scripts/pre-tool-hook +26 -15
- package/scripts/record-cost-event.js +177 -43
- package/scripts/record-cost-event.ts +87 -3
- package/scripts/statusline.sh +169 -0
- package/scripts/stop-hook +21 -11
- package/scripts/tldr-post-edit +72 -0
- package/scripts/tldr-read-enforcer +275 -0
- package/scripts/work-agent-stop-hook +137 -0
- package/skills/check-merged/SKILL.md +143 -0
- package/skills/crash-investigation/SKILL.md +301 -0
- package/skills/github-cli/SKILL.md +185 -0
- package/skills/myn-standards/SKILL.md +351 -0
- package/skills/pan-reopen/SKILL.md +65 -0
- package/skills/pan-sync-main/SKILL.md +87 -0
- package/skills/pan-tldr/SKILL.md +149 -0
- package/skills/react-best-practices/SKILL.md +125 -0
- package/skills/spec-readiness/REPORT-TEMPLATE.md +158 -0
- package/skills/spec-readiness/SCORING-REFERENCE.md +369 -0
- package/skills/spec-readiness/SKILL.md +400 -0
- package/skills/spec-readiness-setup/SKILL.md +361 -0
- package/skills/workspace-status/SKILL.md +56 -0
- package/skills/write-spec/SKILL.md +138 -0
- package/templates/traefik/dynamic/panopticon.yml.template +0 -5
- package/templates/traefik/traefik.yml +0 -8
- package/dist/chunk-2NIAOCIC.js.map +0 -1
- package/dist/chunk-3XAB4IXF.js +0 -51
- package/dist/chunk-3XAB4IXF.js.map +0 -1
- package/dist/chunk-6HXKTOD7.js.map +0 -1
- package/dist/chunk-BBCUK6N2.js +0 -241
- package/dist/chunk-BBCUK6N2.js.map +0 -1
- package/dist/chunk-BWGFN44T.js.map +0 -1
- package/dist/chunk-ELK6Q7QI.js +0 -545
- package/dist/chunk-ELK6Q7QI.js.map +0 -1
- package/dist/chunk-JY7R7V4G.js.map +0 -1
- package/dist/chunk-LYSBSZYV.js +0 -1523
- package/dist/chunk-LYSBSZYV.js.map +0 -1
- package/dist/chunk-VIWUCJ4V.js.map +0 -1
- package/dist/chunk-VU4FLXV5.js.map +0 -1
- package/dist/chunk-XP2DXWYP.js.map +0 -1
- package/dist/dashboard/public/assets/index-C7X6LP5Z.css +0 -32
- package/dist/dashboard/public/assets/index-ClYqpcAJ.js +0 -645
- package/dist/feedback-writer-AAKF5BTK.js.map +0 -1
- package/dist/review-status-GWQYY77L.js.map +0 -1
- package/dist/traefik-CUJM6K5Z.js +0 -12
- /package/dist/{agents-BDFHF4T3.js.map → agents-E43Y3HNU.js.map} +0 -0
- /package/dist/{config-BOAMSKTF.js.map → config-4CJNUE3O.js.map} +0 -0
- /package/dist/{dns-L3L2BB27.js.map → dns-7BDJSD3E.js.map} +0 -0
- /package/dist/{projects-VXRUCMLM.js.map → hume-WMAUBBV2.js.map} +0 -0
- /package/dist/{remote-agents-Z3R2A5BN.js.map → projects-JEIVIYC6.js.map} +0 -0
- /package/dist/{specialist-logs-GF3YV4KL.js.map → rally-RKFSWC7E.js.map} +0 -0
- /package/dist/{specialists-JBIW6MP4.js.map → remote-agents-TFSMW7GN.js.map} +0 -0
- /package/dist/{remote-workspace-2G6V2KNP.js.map → remote-workspace-AHVHQEES.js.map} +0 -0
- /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-NTO3EDB3.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-WQG2TYCB.js.map
|