panopticon-cli 0.5.9 → 0.5.11
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/dist/{agents-M2ZOZL3P.js → agents-RL2KUSP3.js} +3 -3
- package/dist/{archive-planning-U3AZAKWI.js → archive-planning-54J6EP6A.js} +3 -3
- package/dist/{chunk-WEQW3EAT.js → chunk-F4XS2FQN.js} +3 -2
- package/dist/chunk-F4XS2FQN.js.map +1 -0
- package/dist/{chunk-OJF4QS3S.js → chunk-GIW2TUWI.js} +2 -2
- package/dist/{chunk-GM22HPYS.js → chunk-H7T35QDO.js} +21 -3
- package/dist/chunk-H7T35QDO.js.map +1 -0
- package/dist/{chunk-MJXYTGK5.js → chunk-JZWCL5S5.js} +2 -2
- package/dist/{chunk-3WDSD2VK.js → chunk-NLN3ZLCN.js} +186 -88
- package/dist/chunk-NLN3ZLCN.js.map +1 -0
- package/dist/{chunk-QQ27EVBD.js → chunk-OMOEGJDB.js} +3 -3
- package/dist/{chunk-4R6ATXYI.js → chunk-PFA5XE2V.js} +1 -37
- package/dist/chunk-PFA5XE2V.js.map +1 -0
- package/dist/{chunk-6OYUJ4AJ.js → chunk-R47UJWF6.js} +2 -2
- package/dist/{chunk-KPGVCGST.js → chunk-S7EJ2OLR.js} +10 -4
- package/dist/chunk-S7EJ2OLR.js.map +1 -0
- package/dist/{chunk-R4KPLLRB.js → chunk-SFX3BG6N.js} +1 -1
- package/dist/chunk-SFX3BG6N.js.map +1 -0
- package/dist/clean-planning-V4SSVU26.js +9 -0
- package/dist/cli/index.js +1111 -901
- package/dist/cli/index.js.map +1 -1
- package/dist/close-issue-5OMOP2FU.js +9 -0
- package/dist/compact-beads-YQDVF6FQ.js +9 -0
- package/dist/dashboard/prompts/merge-agent.md +11 -0
- package/dist/dashboard/prompts/review-agent.md +9 -0
- package/dist/dashboard/prompts/test-agent.md +9 -0
- package/dist/dashboard/prompts/work-agent.md +10 -2
- package/dist/dashboard/public/assets/index-5hYjhhGn.js +826 -0
- package/dist/dashboard/public/assets/index-DIFh3T1V.css +32 -0
- package/dist/dashboard/public/index.html +2 -2
- package/dist/dashboard/server.js +2405 -1754
- package/dist/index.d.ts +8 -3
- package/dist/index.js +3 -3
- package/dist/{label-cleanup-4HJVX6NP.js → label-cleanup-4IVZIPGK.js} +2 -2
- package/dist/{merge-agent-756U4NPX.js → merge-agent-7L7MWJEC.js} +12 -12
- package/dist/{specialist-context-UBVUUFJV.js → specialist-context-L37RF6Z5.js} +3 -3
- package/dist/{specialist-logs-FQRI3AIS.js → specialist-logs-B7UC3UDO.js} +3 -3
- package/dist/{specialists-CXRGSJY3.js → specialists-X4OGA7WX.js} +3 -3
- package/dist/{workspace-manager-OWHLR5BL.js → workspace-manager-6RP5A5HF.js} +2 -2
- package/package.json +1 -1
- package/skills/pan-new-project/SKILL.md +1 -1
- package/skills/pan-oversee/SKILL.md +45 -10
- package/skills/plan/SKILL.md +336 -0
- package/dist/chunk-3WDSD2VK.js.map +0 -1
- package/dist/chunk-4R6ATXYI.js.map +0 -1
- package/dist/chunk-GM22HPYS.js.map +0 -1
- package/dist/chunk-KPGVCGST.js.map +0 -1
- package/dist/chunk-R4KPLLRB.js.map +0 -1
- package/dist/chunk-WEQW3EAT.js.map +0 -1
- package/dist/clean-planning-7Z5YY64X.js +0 -9
- package/dist/close-issue-CTZK777I.js +0 -9
- package/dist/compact-beads-72SHALOL.js +0 -9
- package/dist/dashboard/public/assets/index-Bx4NCn9A.css +0 -32
- package/dist/dashboard/public/assets/index-DqPey4Of.js +0 -756
- package/skills/opus-plan/SKILL.md +0 -400
- /package/dist/{agents-M2ZOZL3P.js.map → agents-RL2KUSP3.js.map} +0 -0
- /package/dist/{archive-planning-U3AZAKWI.js.map → archive-planning-54J6EP6A.js.map} +0 -0
- /package/dist/{chunk-OJF4QS3S.js.map → chunk-GIW2TUWI.js.map} +0 -0
- /package/dist/{chunk-MJXYTGK5.js.map → chunk-JZWCL5S5.js.map} +0 -0
- /package/dist/{chunk-QQ27EVBD.js.map → chunk-OMOEGJDB.js.map} +0 -0
- /package/dist/{chunk-6OYUJ4AJ.js.map → chunk-R47UJWF6.js.map} +0 -0
- /package/dist/{clean-planning-7Z5YY64X.js.map → clean-planning-V4SSVU26.js.map} +0 -0
- /package/dist/{close-issue-CTZK777I.js.map → close-issue-5OMOP2FU.js.map} +0 -0
- /package/dist/{compact-beads-72SHALOL.js.map → compact-beads-YQDVF6FQ.js.map} +0 -0
- /package/dist/{label-cleanup-4HJVX6NP.js.map → label-cleanup-4IVZIPGK.js.map} +0 -0
- /package/dist/{merge-agent-756U4NPX.js.map → merge-agent-7L7MWJEC.js.map} +0 -0
- /package/dist/{specialist-context-UBVUUFJV.js.map → specialist-context-L37RF6Z5.js.map} +0 -0
- /package/dist/{specialist-logs-FQRI3AIS.js.map → specialist-logs-B7UC3UDO.js.map} +0 -0
- /package/dist/{specialists-CXRGSJY3.js.map → specialists-X4OGA7WX.js.map} +0 -0
- /package/dist/{workspace-manager-OWHLR5BL.js.map → workspace-manager-6RP5A5HF.js.map} +0 -0
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
stopAgent,
|
|
21
21
|
transitionIssueToInProgress,
|
|
22
22
|
transitionIssueToInReview
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-OMOEGJDB.js";
|
|
24
|
+
import "./chunk-PFA5XE2V.js";
|
|
25
25
|
import "./chunk-USYP2SBE.js";
|
|
26
26
|
import "./chunk-QAJAJBFW.js";
|
|
27
27
|
import "./chunk-7ZB5D46Y.js";
|
|
@@ -54,4 +54,4 @@ export {
|
|
|
54
54
|
transitionIssueToInProgress,
|
|
55
55
|
transitionIssueToInReview
|
|
56
56
|
};
|
|
57
|
-
//# sourceMappingURL=agents-
|
|
57
|
+
//# sourceMappingURL=agents-RL2KUSP3.js.map
|
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
archiveWorkspaceArtifacts,
|
|
4
4
|
findWorkspacePath,
|
|
5
5
|
movePrd
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-R47UJWF6.js";
|
|
7
|
+
import "./chunk-SFX3BG6N.js";
|
|
8
8
|
import "./chunk-ZTFNYOC7.js";
|
|
9
9
|
import "./chunk-ZHC57RCV.js";
|
|
10
10
|
export {
|
|
@@ -13,4 +13,4 @@ export {
|
|
|
13
13
|
findWorkspacePath,
|
|
14
14
|
movePrd
|
|
15
15
|
};
|
|
16
|
-
//# sourceMappingURL=archive-planning-
|
|
16
|
+
//# sourceMappingURL=archive-planning-54J6EP6A.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
stepFailed,
|
|
3
3
|
stepOk,
|
|
4
4
|
stepSkipped
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SFX3BG6N.js";
|
|
6
6
|
import {
|
|
7
7
|
init_esm_shims
|
|
8
8
|
} from "./chunk-ZHC57RCV.js";
|
|
@@ -15,6 +15,7 @@ var execAsync = promisify(exec);
|
|
|
15
15
|
var EPHEMERAL_PLANNING_FILES = [
|
|
16
16
|
".planning/STATE.md",
|
|
17
17
|
".planning/PRD.md",
|
|
18
|
+
".planning/WORKSPACE.md",
|
|
18
19
|
".planning/PLANNING_PROMPT.md",
|
|
19
20
|
".planning/PLANNING_PROMPT.md.archived",
|
|
20
21
|
".planning/.planning-complete"
|
|
@@ -75,4 +76,4 @@ async function cleanPlanningArtifacts(ctx) {
|
|
|
75
76
|
export {
|
|
76
77
|
cleanPlanningArtifacts
|
|
77
78
|
};
|
|
78
|
-
//# sourceMappingURL=chunk-
|
|
79
|
+
//# sourceMappingURL=chunk-F4XS2FQN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/lifecycle/clean-planning.ts"],"sourcesContent":["/**\n * clean-planning — Remove ephemeral .planning/ artifacts from main after merge.\n *\n * After a feature branch merges to main, ephemeral planning files\n * (STATE.md, PRD.md, PLANNING_PROMPT.md, .planning-complete, feedback/)\n * land on main and pollute new workspaces that inherit them.\n *\n * This module removes those files from the git index and working tree\n * with a dedicated commit, so new workspaces start clean.\n *\n * Idempotent — if none of the target files are tracked, returns skipped.\n */\n\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport type { LifecycleContext, StepResult } from './types.js';\nimport { stepOk, stepSkipped, stepFailed } from './types.js';\n\nconst execAsync = promisify(exec);\n\n/** Ephemeral planning files to remove from main after merge */\nconst EPHEMERAL_PLANNING_FILES = [\n '.planning/STATE.md',\n '.planning/PRD.md',\n '.planning/WORKSPACE.md',\n '.planning/PLANNING_PROMPT.md',\n '.planning/PLANNING_PROMPT.md.archived',\n '.planning/.planning-complete',\n];\n\n/**\n * Remove ephemeral planning artifacts from main after a feature branch merge.\n *\n * Uses `git rm` to remove tracked files from both the index and working tree,\n * then commits the deletion. Untracked files are silently skipped.\n */\nexport async function cleanPlanningArtifacts(\n ctx: LifecycleContext,\n): Promise<StepResult> {\n const step = 'clean-planning';\n const { issueId, projectPath } = ctx;\n\n try {\n // Build the list of files git is currently tracking in .planning/\n // that match our ephemeral set. We include feedback/ glob separately.\n let trackedFiles: string[] = [];\n\n // Check individual ephemeral files\n for (const file of EPHEMERAL_PLANNING_FILES) {\n try {\n const { stdout } = await execAsync(\n `git ls-files -- ${file}`,\n { cwd: projectPath, encoding: 'utf-8' },\n );\n if (stdout.trim()) {\n trackedFiles.push(file);\n }\n } catch {\n // git ls-files failure is non-fatal\n }\n }\n\n // Check feedback/ directory\n try {\n const { stdout } = await execAsync(\n `git ls-files -- .planning/feedback/`,\n { cwd: projectPath, encoding: 'utf-8' },\n );\n if (stdout.trim()) {\n trackedFiles.push('.planning/feedback/');\n }\n } catch {\n // Non-fatal\n }\n\n if (trackedFiles.length === 0) {\n return stepSkipped(step, ['No tracked ephemeral planning files found on main']);\n }\n\n // Remove tracked files from index and working tree\n const fileArgs = trackedFiles.map(f => `\"${f}\"`).join(' ');\n await execAsync(\n `git rm -rf --ignore-unmatch ${fileArgs}`,\n { cwd: projectPath, encoding: 'utf-8' },\n );\n\n // Check if anything was actually staged for deletion\n try {\n await execAsync('git diff --cached --quiet', { cwd: projectPath, encoding: 'utf-8' });\n // Nothing staged — files may have already been removed\n return stepSkipped(step, ['No staged deletions after git rm (already clean)']);\n } catch {\n // There are staged changes — commit them\n await execAsync(\n `git commit -m \"chore: remove ephemeral planning state after ${issueId} merge\"`,\n { cwd: projectPath, encoding: 'utf-8' },\n );\n }\n\n return stepOk(step, [\n `Removed ${trackedFiles.length} ephemeral planning file(s) from main`,\n `Files: ${trackedFiles.join(', ')}`,\n ]);\n } catch (err) {\n return stepFailed(step, `Failed to clean planning artifacts: ${(err as Error).message}`);\n }\n}\n"],"mappings":";;;;;;;;;;AAAA;AAaA,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAI1B,IAAM,YAAY,UAAU,IAAI;AAGhC,IAAM,2BAA2B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQA,eAAsB,uBACpB,KACqB;AACrB,QAAM,OAAO;AACb,QAAM,EAAE,SAAS,YAAY,IAAI;AAEjC,MAAI;AAGF,QAAI,eAAyB,CAAC;AAG9B,eAAW,QAAQ,0BAA0B;AAC3C,UAAI;AACF,cAAM,EAAE,OAAO,IAAI,MAAM;AAAA,UACvB,mBAAmB,IAAI;AAAA,UACvB,EAAE,KAAK,aAAa,UAAU,QAAQ;AAAA,QACxC;AACA,YAAI,OAAO,KAAK,GAAG;AACjB,uBAAa,KAAK,IAAI;AAAA,QACxB;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,QAAI;AACF,YAAM,EAAE,OAAO,IAAI,MAAM;AAAA,QACvB;AAAA,QACA,EAAE,KAAK,aAAa,UAAU,QAAQ;AAAA,MACxC;AACA,UAAI,OAAO,KAAK,GAAG;AACjB,qBAAa,KAAK,qBAAqB;AAAA,MACzC;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,QAAI,aAAa,WAAW,GAAG;AAC7B,aAAO,YAAY,MAAM,CAAC,mDAAmD,CAAC;AAAA,IAChF;AAGA,UAAM,WAAW,aAAa,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG;AACzD,UAAM;AAAA,MACJ,+BAA+B,QAAQ;AAAA,MACvC,EAAE,KAAK,aAAa,UAAU,QAAQ;AAAA,IACxC;AAGA,QAAI;AACF,YAAM,UAAU,6BAA6B,EAAE,KAAK,aAAa,UAAU,QAAQ,CAAC;AAEpF,aAAO,YAAY,MAAM,CAAC,kDAAkD,CAAC;AAAA,IAC/E,QAAQ;AAEN,YAAM;AAAA,QACJ,+DAA+D,OAAO;AAAA,QACtE,EAAE,KAAK,aAAa,UAAU,QAAQ;AAAA,MACxC;AAAA,IACF;AAEA,WAAO,OAAO,MAAM;AAAA,MAClB,WAAW,aAAa,MAAM;AAAA,MAC9B,UAAU,aAAa,KAAK,IAAI,CAAC;AAAA,IACnC,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,WAAW,MAAM,uCAAwC,IAAc,OAAO,EAAE;AAAA,EACzF;AACF;","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
stepFailed,
|
|
4
4
|
stepOk,
|
|
5
5
|
stepSkipped
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SFX3BG6N.js";
|
|
7
7
|
import {
|
|
8
8
|
init_esm_shims
|
|
9
9
|
} from "./chunk-ZHC57RCV.js";
|
|
@@ -266,4 +266,4 @@ async function applyLabelLinear(ctx, apiKey) {
|
|
|
266
266
|
export {
|
|
267
267
|
closeIssue
|
|
268
268
|
};
|
|
269
|
-
//# sourceMappingURL=chunk-
|
|
269
|
+
//# sourceMappingURL=chunk-GIW2TUWI.js.map
|
|
@@ -182,13 +182,28 @@ function isPanopticonSymlink(targetPath) {
|
|
|
182
182
|
return false;
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
|
-
function
|
|
185
|
+
function migrateStalePersonalContent() {
|
|
186
186
|
const claudeDir = join3(homedir2(), ".claude");
|
|
187
187
|
const result = {
|
|
188
188
|
removedSymlinks: [],
|
|
189
189
|
preservedUserContent: [],
|
|
190
190
|
errors: []
|
|
191
191
|
};
|
|
192
|
+
const devrootNames = /* @__PURE__ */ new Set();
|
|
193
|
+
const devroot = getDevrootPath();
|
|
194
|
+
if (devroot) {
|
|
195
|
+
for (const subdir of ["skills", "commands", "agents"]) {
|
|
196
|
+
const devrootDir = join3(devroot, ".claude", subdir);
|
|
197
|
+
if (existsSync3(devrootDir)) {
|
|
198
|
+
try {
|
|
199
|
+
for (const entry of readdirSync2(devrootDir)) {
|
|
200
|
+
devrootNames.add(`${subdir}/${entry}`);
|
|
201
|
+
}
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
192
207
|
for (const subdir of ["skills", "commands", "agents"]) {
|
|
193
208
|
const dir = join3(claudeDir, subdir);
|
|
194
209
|
if (!existsSync3(dir)) continue;
|
|
@@ -206,6 +221,9 @@ function migrateFromPersonalSymlinks() {
|
|
|
206
221
|
} else {
|
|
207
222
|
result.preservedUserContent.push(`${subdir}/${entry}`);
|
|
208
223
|
}
|
|
224
|
+
} else if (stats.isDirectory() && devrootNames.has(`${subdir}/${entry}`)) {
|
|
225
|
+
rmSync2(entryPath, { recursive: true, force: true });
|
|
226
|
+
result.removedSymlinks.push(`${subdir}/${entry} (stale copy)`);
|
|
209
227
|
} else {
|
|
210
228
|
result.preservedUserContent.push(`${subdir}/${entry}`);
|
|
211
229
|
}
|
|
@@ -662,7 +680,7 @@ export {
|
|
|
662
680
|
restoreBackup,
|
|
663
681
|
cleanOldBackups,
|
|
664
682
|
isPanopticonSymlink,
|
|
665
|
-
|
|
683
|
+
migrateStalePersonalContent,
|
|
666
684
|
refreshCache,
|
|
667
685
|
planSync,
|
|
668
686
|
executeSync,
|
|
@@ -674,4 +692,4 @@ export {
|
|
|
674
692
|
LinkManager,
|
|
675
693
|
getLinkManager
|
|
676
694
|
};
|
|
677
|
-
//# sourceMappingURL=chunk-
|
|
695
|
+
//# sourceMappingURL=chunk-H7T35QDO.js.map
|
|
@@ -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 nothing remains to clean up.\n *\n * Removes two kinds of stale Panopticon content from ~/.claude/:\n * 1. Symlinks pointing to .panopticon or panopticon-cli (legacy sync method)\n * 2. Plain directories that also exist in the devroot (stale copies from before\n * the devroot migration — these cause duplicate skill listings)\n */\nexport function migrateStalePersonalContent(): MigrationResult {\n const claudeDir = join(homedir(), '.claude');\n const result: MigrationResult = {\n removedSymlinks: [],\n preservedUserContent: [],\n errors: [],\n };\n\n // Build a set of skill/agent/command names that exist in the devroot\n // so we can identify stale copies in ~/.claude/\n const devrootNames = new Set<string>();\n const devroot = getDevrootPath();\n if (devroot) {\n for (const subdir of ['skills', 'commands', 'agents']) {\n const devrootDir = join(devroot, '.claude', subdir);\n if (existsSync(devrootDir)) {\n try {\n for (const entry of readdirSync(devrootDir)) {\n devrootNames.add(`${subdir}/${entry}`);\n }\n } catch {\n // Ignore read errors on devroot\n }\n }\n }\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 if (stats.isDirectory() && devrootNames.has(`${subdir}/${entry}`)) {\n // Plain directory that also exists in devroot — stale Panopticon copy.\n // The devroot copy is the canonical one; this personal copy causes\n // duplicate listings and violates principle #4 (never touch ~/.claude/).\n rmSync(entryPath, { recursive: true, force: true });\n result.removedSymlinks.push(`${subdir}/${entry} (stale copy)`);\n } else {\n // Real file/directory with no devroot counterpart — 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","rmSync","mkdirSync","readFileSync","readFileSync","writeFileSync","existsSync","mkdirSync","join","homedir"]}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
stepFailed,
|
|
3
3
|
stepOk,
|
|
4
4
|
stepSkipped
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SFX3BG6N.js";
|
|
6
6
|
import {
|
|
7
7
|
init_esm_shims
|
|
8
8
|
} from "./chunk-ZHC57RCV.js";
|
|
@@ -61,4 +61,4 @@ async function compactBeads(ctx, opts = {}) {
|
|
|
61
61
|
export {
|
|
62
62
|
compactBeads
|
|
63
63
|
};
|
|
64
|
-
//# sourceMappingURL=chunk-
|
|
64
|
+
//# sourceMappingURL=chunk-JZWCL5S5.js.map
|