subconscious-cli 6.3.1 → 8.0.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.
@@ -1,103 +0,0 @@
1
- import crypto from 'node:crypto';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
-
5
- // Claude Code finds an enabled plugin that installed_plugins.json does not
6
- // list (a marketplace plugin pinned to a git SHA, for example) by its place
7
- // in its own cache: <config dir>/plugins/cache/<marketplace>/<plugin>/<version>.
8
- // The subc config dir never links that cache, so such a plugin, and the MCP
9
- // servers it ships, would not load. Each missing version is copied once. A
10
- // copy, unlike a link, cannot carry a cache sweep or orphan marker made in a
11
- // subc session back into ~/.claude.
12
-
13
- // A marketplace or plugin name used as one path segment.
14
- const SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
15
-
16
- /** `[plugin, marketplace]` of an enabledPlugins key, or `undefined`. */
17
- function parsePluginId(id) {
18
- const at = id.lastIndexOf('@');
19
- if (at <= 0) return undefined;
20
- const plugin = id.slice(0, at);
21
- const marketplace = id.slice(at + 1);
22
- return SAFE_NAME.test(plugin) && SAFE_NAME.test(marketplace)
23
- ? [plugin, marketplace]
24
- : undefined;
25
- }
26
-
27
- function copyVersion(from, to) {
28
- // A copy is renamed into place only when complete, so a launch stopped
29
- // half way never leaves a partial plugin that later launches skip.
30
- const temp = `${to}.${crypto.randomBytes(6).toString('hex')}.tmp`;
31
- try {
32
- fs.cpSync(from, temp, { recursive: true, verbatimSymlinks: true });
33
- fs.renameSync(temp, to);
34
- } finally {
35
- fs.rmSync(temp, { recursive: true, force: true });
36
- }
37
- }
38
-
39
- /** Whether `base` or any folder from it down through `parts` is a link. */
40
- function linkOnPath(base, parts) {
41
- let current = base;
42
- for (const part of ['', ...parts]) {
43
- current = part ? path.join(current, part) : current;
44
- try {
45
- if (fs.lstatSync(current).isSymbolicLink()) return true;
46
- } catch {
47
- return false;
48
- }
49
- }
50
- return false;
51
- }
52
-
53
- function directories(dir) {
54
- try {
55
- return fs
56
- .readdirSync(dir, { withFileTypes: true })
57
- .filter((entry) => entry.isDirectory() && SAFE_NAME.test(entry.name))
58
- .map((entry) => entry.name);
59
- } catch {
60
- return [];
61
- }
62
- }
63
-
64
- /**
65
- * Copy into `dir`'s plugin cache every cached version of each enabled plugin
66
- * that the plugin index does not list, unless a copy is already there.
67
- *
68
- * @param {{ dir: string, source: string, enabledPlugins: unknown,
69
- * indexed: unknown, warnings: string[] }} options
70
- */
71
- export function copyUnindexedPlugins({
72
- dir,
73
- source,
74
- enabledPlugins,
75
- indexed,
76
- warnings,
77
- }) {
78
- if (!enabledPlugins || typeof enabledPlugins !== 'object') return;
79
- const listed =
80
- indexed && typeof indexed === 'object' ? Object.keys(indexed) : [];
81
- for (const [id, enabled] of Object.entries(enabledPlugins)) {
82
- if (enabled !== true || listed.includes(id)) continue;
83
- const parsed = parsePluginId(id);
84
- if (!parsed) continue;
85
- const [plugin, marketplace] = parsed;
86
- const from = path.join(source, 'plugins', 'cache', marketplace, plugin);
87
- const to = path.join(dir, 'plugins', 'cache', marketplace, plugin);
88
- // A link here could carry the copy into the user's own cache.
89
- if (linkOnPath(path.join(dir, 'plugins'), ['cache', marketplace, plugin])) {
90
- warnings.push(`Skipped plugin ${id} for subc: its cache path is a link.`);
91
- continue;
92
- }
93
- for (const version of directories(from)) {
94
- if (fs.existsSync(path.join(to, version))) continue;
95
- try {
96
- fs.mkdirSync(to, { recursive: true });
97
- copyVersion(path.join(from, version), path.join(to, version));
98
- } catch (error) {
99
- warnings.push(`Could not copy plugin ${id} for subc: ${error.message}`);
100
- }
101
- }
102
- }
103
- }