@nexrall/code-core 1.4.76 → 1.4.78
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/agent/effortCap.d.ts +24 -0
- package/dist/agent/effortCap.d.ts.map +1 -0
- package/dist/agent/effortCap.js +66 -0
- package/dist/agent/goal.d.ts +55 -0
- package/dist/agent/goal.d.ts.map +1 -0
- package/dist/agent/goal.js +120 -0
- package/dist/agent/handoffBrief.d.ts +82 -0
- package/dist/agent/handoffBrief.d.ts.map +1 -0
- package/dist/agent/handoffBrief.js +121 -0
- package/dist/agent/hooks.d.ts +10 -2
- package/dist/agent/hooks.d.ts.map +1 -1
- package/dist/agent/hooks.js +9 -3
- package/dist/agent/modelCatalogue.d.ts +23 -0
- package/dist/agent/modelCatalogue.d.ts.map +1 -1
- package/dist/agent/modelCatalogue.js +28 -0
- package/dist/agent/outputStyles.d.ts +27 -0
- package/dist/agent/outputStyles.d.ts.map +1 -0
- package/dist/agent/outputStyles.js +174 -0
- package/dist/agent/skills.d.ts.map +1 -1
- package/dist/agent/skills.js +21 -1
- package/dist/api/billingLines.d.ts +11 -0
- package/dist/api/billingLines.d.ts.map +1 -0
- package/dist/api/billingLines.js +56 -0
- package/dist/api/client.d.ts +2 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/scheduleLines.d.ts +53 -0
- package/dist/api/scheduleLines.d.ts.map +1 -0
- package/dist/api/scheduleLines.js +150 -0
- package/dist/context/contextFiles.d.ts +81 -0
- package/dist/context/contextFiles.d.ts.map +1 -0
- package/dist/context/contextFiles.js +310 -0
- package/dist/diff/collect.d.ts +25 -0
- package/dist/diff/collect.d.ts.map +1 -0
- package/dist/diff/collect.js +169 -0
- package/dist/diff/diffView.d.ts +57 -0
- package/dist/diff/diffView.d.ts.map +1 -0
- package/dist/diff/diffView.js +231 -0
- package/dist/diff/reviewQueue.d.ts +53 -0
- package/dist/diff/reviewQueue.d.ts.map +1 -0
- package/dist/diff/reviewQueue.js +349 -0
- package/dist/events/recap.d.ts +54 -0
- package/dist/events/recap.d.ts.map +1 -0
- package/dist/events/recap.js +161 -0
- package/dist/events/sessionEvents.d.ts +54 -0
- package/dist/events/sessionEvents.d.ts.map +1 -0
- package/dist/events/sessionEvents.js +324 -0
- package/dist/events/sessionStats.d.ts +89 -0
- package/dist/events/sessionStats.d.ts.map +1 -0
- package/dist/events/sessionStats.js +264 -0
- package/dist/import/claudeImport.d.ts +44 -0
- package/dist/import/claudeImport.d.ts.map +1 -0
- package/dist/import/claudeImport.js +337 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -0
- package/dist/mcp/manager.d.ts +8 -0
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +64 -57
- package/dist/permissions/destructiveTokens.d.ts +1 -0
- package/dist/permissions/destructiveTokens.d.ts.map +1 -1
- package/dist/permissions/destructiveTokens.js +93 -0
- package/dist/permissions/rules.d.ts +12 -0
- package/dist/permissions/rules.d.ts.map +1 -1
- package/dist/permissions/rules.js +89 -7
- package/dist/plugins/configStore.d.ts +43 -0
- package/dist/plugins/configStore.d.ts.map +1 -0
- package/dist/plugins/configStore.js +253 -0
- package/dist/plugins/files.d.ts +10 -0
- package/dist/plugins/files.d.ts.map +1 -0
- package/dist/plugins/files.js +85 -0
- package/dist/plugins/index.d.ts +3 -22
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +30 -40
- package/dist/plugins/resolve.d.ts +18 -0
- package/dist/plugins/resolve.d.ts.map +1 -0
- package/dist/plugins/resolve.js +152 -0
- package/dist/plugins/userConfig.d.ts +90 -0
- package/dist/plugins/userConfig.d.ts.map +1 -0
- package/dist/plugins/userConfig.js +332 -0
- package/dist/plugins/validate.d.ts +14 -0
- package/dist/plugins/validate.d.ts.map +1 -0
- package/dist/plugins/validate.js +222 -0
- package/dist/project/projectCommands.d.ts +33 -0
- package/dist/project/projectCommands.d.ts.map +1 -0
- package/dist/project/projectCommands.js +246 -0
- package/dist/search/conversationTurns.d.ts +53 -0
- package/dist/search/conversationTurns.d.ts.map +1 -0
- package/dist/search/conversationTurns.js +170 -0
- package/dist/search/globalSearch.d.ts +144 -0
- package/dist/search/globalSearch.d.ts.map +1 -0
- package/dist/search/globalSearch.js +350 -0
- package/dist/share/sessionChannel.d.ts +136 -0
- package/dist/share/sessionChannel.d.ts.map +1 -0
- package/dist/share/sessionChannel.js +373 -0
- package/dist/share/sessionShare.d.ts +104 -0
- package/dist/share/sessionShare.d.ts.map +1 -0
- package/dist/share/sessionShare.js +336 -0
- package/dist/ui/configCmd.d.ts +48 -0
- package/dist/ui/configCmd.d.ts.map +1 -0
- package/dist/ui/configCmd.js +146 -0
- package/dist/ui/deployPanel.d.ts +91 -0
- package/dist/ui/deployPanel.d.ts.map +1 -0
- package/dist/ui/deployPanel.js +442 -0
- package/dist/ui/mergeAssistant.d.ts +120 -0
- package/dist/ui/mergeAssistant.d.ts.map +1 -0
- package/dist/ui/mergeAssistant.js +391 -0
- package/dist/ui/notify.d.ts +114 -0
- package/dist/ui/notify.d.ts.map +1 -0
- package/dist/ui/notify.js +235 -0
- package/dist/ui/promptSuggest.d.ts +56 -0
- package/dist/ui/promptSuggest.d.ts.map +1 -0
- package/dist/ui/promptSuggest.js +160 -0
- package/dist/ui/taskGraph.d.ts +44 -0
- package/dist/ui/taskGraph.d.ts.map +1 -0
- package/dist/ui/taskGraph.js +289 -0
- package/dist/util/addDir.d.ts +31 -0
- package/dist/util/addDir.d.ts.map +1 -0
- package/dist/util/addDir.js +124 -0
- package/dist/util/batch.d.ts +16 -0
- package/dist/util/batch.d.ts.map +1 -0
- package/dist/util/batch.js +92 -0
- package/dist/util/cellWidth.d.ts +12 -0
- package/dist/util/cellWidth.d.ts.map +1 -0
- package/dist/util/cellWidth.js +161 -0
- package/dist/util/duration.d.ts +8 -0
- package/dist/util/duration.d.ts.map +1 -0
- package/dist/util/duration.js +50 -0
- package/dist/util/loopJobs.d.ts +67 -0
- package/dist/util/loopJobs.d.ts.map +1 -0
- package/dist/util/loopJobs.js +169 -0
- package/dist/util/settingsFile.d.ts +14 -0
- package/dist/util/settingsFile.d.ts.map +1 -0
- package/dist/util/settingsFile.js +99 -0
- package/dist/util/toolLabel.d.ts +2 -0
- package/dist/util/toolLabel.d.ts.map +1 -0
- package/dist/util/toolLabel.js +17 -0
- package/dist/verify/failureTimeline.d.ts +100 -0
- package/dist/verify/failureTimeline.d.ts.map +1 -0
- package/dist/verify/failureTimeline.js +253 -0
- package/dist/verify/verification.d.ts +75 -0
- package/dist/verify/verification.d.ts.map +1 -0
- package/dist/verify/verification.js +315 -0
- package/package.json +5 -4
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─── Plugin config values store (S24) ────────────────────────────────────────
|
|
3
|
+
//
|
|
4
|
+
// Where a plugin's userConfig VALUES live:
|
|
5
|
+
//
|
|
6
|
+
// • non-sensitive → `pluginConfigs.<plugin>.<key>` in a settings file
|
|
7
|
+
// (managed → user → project → local → `--settings`, read merged; the LAST
|
|
8
|
+
// tier wins per key, matching every other settings read in the codebase).
|
|
9
|
+
// Written to the tier you choose — default: the scope the plugin is
|
|
10
|
+
// installed in, so a project plugin configures itself in the project.
|
|
11
|
+
// • sensitive → `~/.nexrall/plugin-secrets.json` (0600), keyed the same way.
|
|
12
|
+
// Claude Code uses the OS credential store here; the CLI has no such
|
|
13
|
+
// integration, so this is a dedicated 0600 file instead — stated plainly
|
|
14
|
+
// rather than implied to be a keychain.
|
|
15
|
+
// • nothing set → the manifest default (resolvePluginConfig reports which).
|
|
16
|
+
//
|
|
17
|
+
// Resolution order per key: secrets → settings → default. An INVALID value at
|
|
18
|
+
// a higher precedence does not win: it is reported (resolvePluginConfig's
|
|
19
|
+
// `invalid`) and resolution continues to the next source, so a typo in
|
|
20
|
+
// settings cannot silently break a working default.
|
|
21
|
+
//
|
|
22
|
+
// This module reads/writes the disk; the schema and substitution half is pure
|
|
23
|
+
// (userConfig.ts).
|
|
24
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
27
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
28
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
29
|
+
}
|
|
30
|
+
Object.defineProperty(o, k2, desc);
|
|
31
|
+
}) : (function(o, m, k, k2) {
|
|
32
|
+
if (k2 === undefined) k2 = k;
|
|
33
|
+
o[k2] = m[k];
|
|
34
|
+
}));
|
|
35
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
36
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
37
|
+
}) : function(o, v) {
|
|
38
|
+
o["default"] = v;
|
|
39
|
+
});
|
|
40
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
41
|
+
var ownKeys = function(o) {
|
|
42
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
43
|
+
var ar = [];
|
|
44
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
45
|
+
return ar;
|
|
46
|
+
};
|
|
47
|
+
return ownKeys(o);
|
|
48
|
+
};
|
|
49
|
+
return function (mod) {
|
|
50
|
+
if (mod && mod.__esModule) return mod;
|
|
51
|
+
var result = {};
|
|
52
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
53
|
+
__setModuleDefault(result, mod);
|
|
54
|
+
return result;
|
|
55
|
+
};
|
|
56
|
+
})();
|
|
57
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
|
+
exports.readPluginSecrets = readPluginSecrets;
|
|
59
|
+
exports.pluginConfigsFromSettings = pluginConfigsFromSettings;
|
|
60
|
+
exports.resolvePluginConfig = resolvePluginConfig;
|
|
61
|
+
exports.savePluginConfig = savePluginConfig;
|
|
62
|
+
const fs = __importStar(require("fs"));
|
|
63
|
+
const os = __importStar(require("os"));
|
|
64
|
+
const path = __importStar(require("path"));
|
|
65
|
+
const rules_1 = require("../permissions/rules");
|
|
66
|
+
const userConfig_1 = require("./userConfig");
|
|
67
|
+
// NOTE (import graph): this module deliberately does NOT use
|
|
68
|
+
// util/settingsFile's writeSetting — that module imports agent/hooks, and
|
|
69
|
+
// hooks imports plugins/resolve → this file; using it would close a cycle.
|
|
70
|
+
// The atomic write below is the same temp-file+rename shape, minus the
|
|
71
|
+
// ConfigChange observer hook (pluginConfig edits do not fire it yet).
|
|
72
|
+
function secretsPath() {
|
|
73
|
+
return path.join(os.homedir(), '.nexrall', 'plugin-secrets.json');
|
|
74
|
+
}
|
|
75
|
+
/** The settings file a scoped write targets (mirror of util/settingsFile's settingsPath). */
|
|
76
|
+
function tierFile(workDir, scope) {
|
|
77
|
+
return scope === 'project'
|
|
78
|
+
? path.join(workDir, '.nexrall', 'settings.json')
|
|
79
|
+
: path.join(os.homedir(), '.nexrall', 'settings.json');
|
|
80
|
+
}
|
|
81
|
+
/** Atomic top-level-key write: temp file + rename, so an interrupted write cannot half-JSON a settings file. */
|
|
82
|
+
function writeTierSetting(workDir, scope, key, value) {
|
|
83
|
+
const file = tierFile(workDir, scope);
|
|
84
|
+
let existing = {};
|
|
85
|
+
if (fs.existsSync(file)) {
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
88
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
|
|
89
|
+
existing = parsed;
|
|
90
|
+
else
|
|
91
|
+
return { ok: false, path: file, error: 'the file is valid JSON but not an object' };
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
return { ok: false, path: file, error: `could not parse it: ${e.message}` };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const next = { ...existing };
|
|
98
|
+
if (value === undefined)
|
|
99
|
+
delete next[key];
|
|
100
|
+
else
|
|
101
|
+
next[key] = value;
|
|
102
|
+
try {
|
|
103
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
104
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
105
|
+
fs.writeFileSync(tmp, JSON.stringify(next, null, 2) + '\n', 'utf-8');
|
|
106
|
+
fs.renameSync(tmp, file);
|
|
107
|
+
return { ok: true, path: file };
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
return { ok: false, path: file, error: e.message };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** The whole secrets file ({} when absent/unreadable/malformed). */
|
|
114
|
+
function readPluginSecrets() {
|
|
115
|
+
try {
|
|
116
|
+
const j = JSON.parse(fs.readFileSync(secretsPath(), 'utf-8'));
|
|
117
|
+
if (!j || typeof j !== 'object' || Array.isArray(j))
|
|
118
|
+
return {};
|
|
119
|
+
return j;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return {};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/** Write the secrets file 0600. Best-effort: a read-only home must not crash a save that the settings half may still complete. */
|
|
126
|
+
function writePluginSecrets(map) {
|
|
127
|
+
const file = secretsPath();
|
|
128
|
+
try {
|
|
129
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
130
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
131
|
+
fs.writeFileSync(tmp, JSON.stringify(map, null, 2) + '\n', { encoding: 'utf-8', mode: 0o600 });
|
|
132
|
+
fs.renameSync(tmp, file);
|
|
133
|
+
return { ok: true };
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
return { ok: false, error: e.message };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* `pluginConfigs` from every settings tier, merged per plugin per key
|
|
141
|
+
* (last tier wins — the same direction loadSettings uses for `raw`).
|
|
142
|
+
*/
|
|
143
|
+
function pluginConfigsFromSettings(workDir) {
|
|
144
|
+
const out = {};
|
|
145
|
+
for (const { raw } of (0, rules_1.settingsTiersRaw)(workDir)) {
|
|
146
|
+
const pc = raw.pluginConfigs;
|
|
147
|
+
if (!pc || typeof pc !== 'object' || Array.isArray(pc))
|
|
148
|
+
continue;
|
|
149
|
+
for (const [plugin, bag] of Object.entries(pc)) {
|
|
150
|
+
if (!bag || typeof bag !== 'object' || Array.isArray(bag))
|
|
151
|
+
continue;
|
|
152
|
+
out[plugin] = { ...(out[plugin] ?? {}), ...bag };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
/** Resolve every declared option to its effective value. Pure reads. */
|
|
158
|
+
function resolvePluginConfig(workDir, pluginName, options) {
|
|
159
|
+
const secrets = readPluginSecrets()[pluginName] ?? {};
|
|
160
|
+
const fromSettings = pluginConfigsFromSettings(workDir)[pluginName] ?? {};
|
|
161
|
+
const values = {};
|
|
162
|
+
const sources = {};
|
|
163
|
+
const invalid = [];
|
|
164
|
+
for (const option of options) {
|
|
165
|
+
let found = false;
|
|
166
|
+
for (const [source, bag] of [
|
|
167
|
+
['secret', secrets],
|
|
168
|
+
['settings', fromSettings],
|
|
169
|
+
]) {
|
|
170
|
+
if (!(option.key in bag))
|
|
171
|
+
continue;
|
|
172
|
+
const err = (0, userConfig_1.validateUserConfigValue)(option, bag[option.key]);
|
|
173
|
+
if (err) {
|
|
174
|
+
invalid.push({ key: option.key, source, error: err });
|
|
175
|
+
continue; // a broken higher-precedence value must not mask a working lower one
|
|
176
|
+
}
|
|
177
|
+
values[option.key] = bag[option.key];
|
|
178
|
+
sources[option.key] = source;
|
|
179
|
+
found = true;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
if (found)
|
|
183
|
+
continue;
|
|
184
|
+
if (option.default !== undefined) {
|
|
185
|
+
values[option.key] = option.default;
|
|
186
|
+
sources[option.key] = 'default';
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const missing = options.filter((o) => o.required === true && !(o.key in values)).map((o) => o.key);
|
|
190
|
+
return { values, sources, missing, invalid };
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Validate + save values. Unknown keys are errors (a typo must not create a
|
|
194
|
+
* silent no-op entry), as are values that fail their option's validation. The
|
|
195
|
+
* two halves land in different stores (see the file header).
|
|
196
|
+
*/
|
|
197
|
+
function savePluginConfig(workDir, pluginName, options, values, opts = {}) {
|
|
198
|
+
const byKey = new Map(options.map((o) => [o.key, o]));
|
|
199
|
+
const errors = [];
|
|
200
|
+
const plain = {};
|
|
201
|
+
const secret = {};
|
|
202
|
+
for (const [key, value] of Object.entries(values)) {
|
|
203
|
+
const option = byKey.get(key);
|
|
204
|
+
if (!option) {
|
|
205
|
+
errors.push(`"${key}" is not a declared option of plugin "${pluginName}"`);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const bad = (0, userConfig_1.validateUserConfigValue)(option, value);
|
|
209
|
+
if (bad) {
|
|
210
|
+
errors.push(`${key}: ${bad}`);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (option.sensitive)
|
|
214
|
+
secret[key] = value;
|
|
215
|
+
else
|
|
216
|
+
plain[key] = value;
|
|
217
|
+
}
|
|
218
|
+
if (errors.length)
|
|
219
|
+
return { ok: false, errors };
|
|
220
|
+
const result = { ok: true, errors: [] };
|
|
221
|
+
if (Object.keys(secret).length) {
|
|
222
|
+
const map = readPluginSecrets();
|
|
223
|
+
map[pluginName] = { ...(map[pluginName] ?? {}), ...secret };
|
|
224
|
+
const w = writePluginSecrets(map);
|
|
225
|
+
if (!w.ok)
|
|
226
|
+
return { ok: false, errors: [`could not write the secrets file: ${w.error}`] };
|
|
227
|
+
result.wroteSecrets = true;
|
|
228
|
+
}
|
|
229
|
+
if (Object.keys(plain).length) {
|
|
230
|
+
const scope = opts.scope ?? 'user';
|
|
231
|
+
// Read the TARGET tier file's pluginConfigs and merge — the write replaces the
|
|
232
|
+
// whole top-level key, so passing a partial object would drop other plugins.
|
|
233
|
+
const file = tierFile(workDir, scope);
|
|
234
|
+
let tierPc = {};
|
|
235
|
+
try {
|
|
236
|
+
const j = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
237
|
+
const pc = j?.pluginConfigs;
|
|
238
|
+
if (pc && typeof pc === 'object' && !Array.isArray(pc)) {
|
|
239
|
+
tierPc = pc;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
/* no file yet, or unreadable — start from an empty map; the writer refuses a corrupt file itself */
|
|
244
|
+
}
|
|
245
|
+
const merged = { ...tierPc, [pluginName]: { ...(tierPc[pluginName] ?? {}), ...plain } };
|
|
246
|
+
const w = writeTierSetting(workDir, scope, 'pluginConfigs', merged);
|
|
247
|
+
if (!w.ok)
|
|
248
|
+
return { ok: false, errors: [`could not write settings: ${w.error}`] };
|
|
249
|
+
result.wroteSettings = w.path;
|
|
250
|
+
}
|
|
251
|
+
return result;
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=configStore.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const FILE_CANDIDATES: {
|
|
2
|
+
readonly manifest: readonly ["plugin.json", string];
|
|
3
|
+
readonly hooks: readonly ["hooks.json", string];
|
|
4
|
+
readonly mcp: readonly ["mcp.json", ".mcp.json"];
|
|
5
|
+
};
|
|
6
|
+
/** First existing candidate path for a component, or null. */
|
|
7
|
+
export declare function resolvePluginFile(dir: string, kind: keyof typeof FILE_CANDIDATES): string | null;
|
|
8
|
+
/** The plugin's manifest as a parsed object (null when absent/malformed/not an object). */
|
|
9
|
+
export declare function readPluginManifest(dir: string): Record<string, unknown> | null;
|
|
10
|
+
//# sourceMappingURL=files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/plugins/files.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,eAAe;;;;CAIlB,CAAC;AAEX,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,eAAe,GAAG,MAAM,GAAG,IAAI,CAUhG;AAED,2FAA2F;AAC3F,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAS9E"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.FILE_CANDIDATES = void 0;
|
|
37
|
+
exports.resolvePluginFile = resolvePluginFile;
|
|
38
|
+
exports.readPluginManifest = readPluginManifest;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
// ─── Component file locations ────────────────────────────────────────────────
|
|
42
|
+
//
|
|
43
|
+
// Extracted from plugins/index.ts (S24) so the modules that PARSE a plugin's
|
|
44
|
+
// files without loading it — userConfig schema reading, `nex plugin validate`,
|
|
45
|
+
// the config store — can resolve paths without importing the loader (which
|
|
46
|
+
// imports them back: a cycle).
|
|
47
|
+
//
|
|
48
|
+
// SECURITY: `hooks` and `mcp` here are code-execution surfaces. Every reader
|
|
49
|
+
// (plugins/index.ts, installer.ts's inspectPluginDir, validate.ts) MUST resolve
|
|
50
|
+
// through this same table - if the loader reads a path the inspector does not
|
|
51
|
+
// check, a plugin can run commands that the install-time warning never
|
|
52
|
+
// mentioned.
|
|
53
|
+
exports.FILE_CANDIDATES = {
|
|
54
|
+
manifest: ['plugin.json', path.join('.claude-plugin', 'plugin.json')],
|
|
55
|
+
hooks: ['hooks.json', path.join('hooks', 'hooks.json')],
|
|
56
|
+
mcp: ['mcp.json', '.mcp.json'],
|
|
57
|
+
};
|
|
58
|
+
/** First existing candidate path for a component, or null. */
|
|
59
|
+
function resolvePluginFile(dir, kind) {
|
|
60
|
+
for (const rel of exports.FILE_CANDIDATES[kind]) {
|
|
61
|
+
const full = path.join(dir, rel);
|
|
62
|
+
try {
|
|
63
|
+
if (fs.statSync(full).isFile())
|
|
64
|
+
return full;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
/* try the next candidate */
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
/** The plugin's manifest as a parsed object (null when absent/malformed/not an object). */
|
|
73
|
+
function readPluginManifest(dir) {
|
|
74
|
+
const file = resolvePluginFile(dir, 'manifest');
|
|
75
|
+
if (!file)
|
|
76
|
+
return null;
|
|
77
|
+
try {
|
|
78
|
+
const j = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
79
|
+
return j && typeof j === 'object' && !Array.isArray(j) ? j : null;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=files.js.map
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { FILE_CANDIDATES, resolvePluginFile, readPluginManifest } from './files';
|
|
1
2
|
export interface PluginInfo {
|
|
2
3
|
/** Directory name (or plugin.json "name" when present). */
|
|
3
4
|
name: string;
|
|
@@ -13,26 +14,6 @@ export interface PluginInfo {
|
|
|
13
14
|
export declare function isPluginDisabled(dir: string): boolean;
|
|
14
15
|
/** Toggle a plugin on/off. Idempotent — enabling an already-enabled plugin is a no-op. */
|
|
15
16
|
export declare function setPluginDisabled(dir: string, disabled: boolean): void;
|
|
16
|
-
/**
|
|
17
|
-
* Where each single-file component may live, in priority order.
|
|
18
|
-
*
|
|
19
|
-
* Our own layout is checked first so a plugin shipping both is unambiguous, and
|
|
20
|
-
* so this stays additive: nothing that worked before changes behaviour.
|
|
21
|
-
*
|
|
22
|
-
* SECURITY: `hooks` and `mcp` here are code-execution surfaces. Every reader
|
|
23
|
-
* below and `inspectPluginDir` in installer.ts MUST resolve through this same
|
|
24
|
-
* table — if the loader reads a path the inspector does not check, a plugin can
|
|
25
|
-
* run commands that the install-time warning never mentioned. Adding a candidate
|
|
26
|
-
* without updating the inspector is exactly that bug, so the two are pinned
|
|
27
|
-
* together by a test.
|
|
28
|
-
*/
|
|
29
|
-
export declare const FILE_CANDIDATES: {
|
|
30
|
-
readonly manifest: readonly ["plugin.json", string];
|
|
31
|
-
readonly hooks: readonly ["hooks.json", string];
|
|
32
|
-
readonly mcp: readonly ["mcp.json", ".mcp.json"];
|
|
33
|
-
};
|
|
34
|
-
/** First existing candidate path for a component, or null. */
|
|
35
|
-
export declare function resolvePluginFile(dir: string, kind: keyof typeof FILE_CANDIDATES): string | null;
|
|
36
17
|
/**
|
|
37
18
|
* Discover installed plugins (project scope shadows global on name clash).
|
|
38
19
|
*
|
|
@@ -65,7 +46,7 @@ export declare function pluginAssetDirs(workDir: string, kind: 'commands' | 'age
|
|
|
65
46
|
* processes their NEXRALL_PLUGIN_DATA (see runHookHandler). Both entry forms are stamped:
|
|
66
47
|
* the flat one (the entry IS the handler) and the nested one (each item under `hooks`).
|
|
67
48
|
*/
|
|
68
|
-
export declare function pluginHooks(workDir: string): Record<string, unknown[]>;
|
|
49
|
+
export declare function pluginHooks(workDir: string, transform?: (entry: unknown, plugin: string) => unknown): Record<string, unknown[]>;
|
|
69
50
|
/** MCP server maps declared by ENABLED plugins: { serverName → config } (first plugin wins on clash).
|
|
70
51
|
*
|
|
71
52
|
* A stdio server from a plugin gets NEXRALL_PLUGIN_DATA in its environment, pointing at the
|
|
@@ -73,5 +54,5 @@ export declare function pluginHooks(workDir: string): Record<string, unknown[]>;
|
|
|
73
54
|
* this is the only place a server can keep state. A plugin that set the variable itself keeps
|
|
74
55
|
* its own value: an explicit config value is never overridden here.
|
|
75
56
|
*/
|
|
76
|
-
export declare function pluginMcpServers(workDir: string): Record<string, unknown>;
|
|
57
|
+
export declare function pluginMcpServers(workDir: string, transform?: (cfg: unknown, plugin: string) => unknown): Record<string, unknown>;
|
|
77
58
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAoCjF,MAAM,WAAW,UAAU;IACzB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,6EAA6E;IAC7E,QAAQ,EAAE,OAAO,CAAC;CACnB;AAYD,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMrD;AAED,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAWtE;AAsDD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CAKzD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAM7G;AAED,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,EAAE,CAWjG;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,GACtD,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CA4B3B;AAeD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,GACpD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuBzB"}
|
package/dist/plugins/index.js
CHANGED
|
@@ -33,10 +33,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.FILE_CANDIDATES = void 0;
|
|
36
|
+
exports.readPluginManifest = exports.resolvePluginFile = exports.FILE_CANDIDATES = void 0;
|
|
37
37
|
exports.isPluginDisabled = isPluginDisabled;
|
|
38
38
|
exports.setPluginDisabled = setPluginDisabled;
|
|
39
|
-
exports.resolvePluginFile = resolvePluginFile;
|
|
40
39
|
exports.loadPlugins = loadPlugins;
|
|
41
40
|
exports.findPlugin = findPlugin;
|
|
42
41
|
exports.pluginAssetDirs = pluginAssetDirs;
|
|
@@ -46,6 +45,11 @@ const fs = __importStar(require("fs"));
|
|
|
46
45
|
const path = __importStar(require("path"));
|
|
47
46
|
const os = __importStar(require("os"));
|
|
48
47
|
const data_1 = require("./data");
|
|
48
|
+
const files_1 = require("./files");
|
|
49
|
+
var files_2 = require("./files");
|
|
50
|
+
Object.defineProperty(exports, "FILE_CANDIDATES", { enumerable: true, get: function () { return files_2.FILE_CANDIDATES; } });
|
|
51
|
+
Object.defineProperty(exports, "resolvePluginFile", { enumerable: true, get: function () { return files_2.resolvePluginFile; } });
|
|
52
|
+
Object.defineProperty(exports, "readPluginManifest", { enumerable: true, get: function () { return files_2.readPluginManifest; } });
|
|
49
53
|
// ─── Enable / disable ──────────────────────────────────────────────────────────
|
|
50
54
|
//
|
|
51
55
|
// A marker file rather than a registry list, so the on/off state travels WITH
|
|
@@ -80,39 +84,13 @@ function setPluginDisabled(dir, disabled) {
|
|
|
80
84
|
}
|
|
81
85
|
}
|
|
82
86
|
/**
|
|
83
|
-
* Where each single-file component may live, in priority order
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* SECURITY: `hooks` and `mcp` here are code-execution surfaces. Every reader
|
|
89
|
-
* below and `inspectPluginDir` in installer.ts MUST resolve through this same
|
|
90
|
-
* table — if the loader reads a path the inspector does not check, a plugin can
|
|
91
|
-
* run commands that the install-time warning never mentioned. Adding a candidate
|
|
92
|
-
* without updating the inspector is exactly that bug, so the two are pinned
|
|
93
|
-
* together by a test.
|
|
87
|
+
* Where each single-file component may live, in priority order — moved to
|
|
88
|
+
* ./files.ts (S24) so parsing-only modules (validate, the config store) can
|
|
89
|
+
* resolve paths without importing this loader (which imports them back).
|
|
90
|
+
* Re-exported above for existing callers.
|
|
94
91
|
*/
|
|
95
|
-
exports.FILE_CANDIDATES = {
|
|
96
|
-
manifest: ['plugin.json', path.join('.claude-plugin', 'plugin.json')],
|
|
97
|
-
hooks: ['hooks.json', path.join('hooks', 'hooks.json')],
|
|
98
|
-
mcp: ['mcp.json', '.mcp.json'],
|
|
99
|
-
};
|
|
100
|
-
/** First existing candidate path for a component, or null. */
|
|
101
|
-
function resolvePluginFile(dir, kind) {
|
|
102
|
-
for (const rel of exports.FILE_CANDIDATES[kind]) {
|
|
103
|
-
const full = path.join(dir, rel);
|
|
104
|
-
try {
|
|
105
|
-
if (fs.statSync(full).isFile())
|
|
106
|
-
return full;
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
/* try the next candidate */
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
92
|
function readMeta(dir) {
|
|
115
|
-
const file = resolvePluginFile(dir, 'manifest');
|
|
93
|
+
const file = (0, files_1.resolvePluginFile)(dir, 'manifest');
|
|
116
94
|
if (!file)
|
|
117
95
|
return {};
|
|
118
96
|
try {
|
|
@@ -215,12 +193,12 @@ function pluginAssetDirs(workDir, kind) {
|
|
|
215
193
|
* processes their NEXRALL_PLUGIN_DATA (see runHookHandler). Both entry forms are stamped:
|
|
216
194
|
* the flat one (the entry IS the handler) and the nested one (each item under `hooks`).
|
|
217
195
|
*/
|
|
218
|
-
function pluginHooks(workDir) {
|
|
196
|
+
function pluginHooks(workDir, transform) {
|
|
219
197
|
const merged = {};
|
|
220
198
|
for (const p of loadPlugins(workDir)) {
|
|
221
199
|
if (p.disabled)
|
|
222
200
|
continue;
|
|
223
|
-
const file = resolvePluginFile(p.dir, 'hooks');
|
|
201
|
+
const file = (0, files_1.resolvePluginFile)(p.dir, 'hooks');
|
|
224
202
|
if (!file)
|
|
225
203
|
continue;
|
|
226
204
|
try {
|
|
@@ -231,7 +209,15 @@ function pluginHooks(workDir) {
|
|
|
231
209
|
for (const [phase, entries] of Object.entries(hooks)) {
|
|
232
210
|
if (!Array.isArray(entries))
|
|
233
211
|
continue;
|
|
234
|
-
|
|
212
|
+
// `transform` (S24) lets plugins/resolve.ts bake each handler's resolved
|
|
213
|
+
// userConfig env map in, keeping THIS loader free of value resolution.
|
|
214
|
+
merged[phase] = [
|
|
215
|
+
...(merged[phase] ?? []),
|
|
216
|
+
...entries.map((e) => {
|
|
217
|
+
const stamped = stampPlugin(e, p.name);
|
|
218
|
+
return transform ? transform(stamped, p.name) : stamped;
|
|
219
|
+
}),
|
|
220
|
+
];
|
|
235
221
|
}
|
|
236
222
|
}
|
|
237
223
|
catch {
|
|
@@ -260,12 +246,12 @@ function stampPlugin(entry, plugin) {
|
|
|
260
246
|
* this is the only place a server can keep state. A plugin that set the variable itself keeps
|
|
261
247
|
* its own value: an explicit config value is never overridden here.
|
|
262
248
|
*/
|
|
263
|
-
function pluginMcpServers(workDir) {
|
|
249
|
+
function pluginMcpServers(workDir, transform) {
|
|
264
250
|
const merged = {};
|
|
265
251
|
for (const p of loadPlugins(workDir)) {
|
|
266
252
|
if (p.disabled)
|
|
267
253
|
continue;
|
|
268
|
-
const file = resolvePluginFile(p.dir, 'mcp');
|
|
254
|
+
const file = (0, files_1.resolvePluginFile)(p.dir, 'mcp');
|
|
269
255
|
if (!file)
|
|
270
256
|
continue;
|
|
271
257
|
try {
|
|
@@ -273,8 +259,12 @@ function pluginMcpServers(workDir) {
|
|
|
273
259
|
const j = JSON.parse(raw);
|
|
274
260
|
const servers = (j.mcpServers ?? j);
|
|
275
261
|
for (const [name, cfg] of Object.entries(servers)) {
|
|
276
|
-
if (!(name in merged))
|
|
277
|
-
|
|
262
|
+
if (!(name in merged)) {
|
|
263
|
+
// `transform` (S24) is where plugins/resolve.ts substitutes
|
|
264
|
+
// `${user_config.KEY}`; the data-dir env is added after it.
|
|
265
|
+
const resolved = transform ? transform(cfg, p.name) : cfg;
|
|
266
|
+
merged[name] = withPluginDataEnv(resolved, p.name);
|
|
267
|
+
}
|
|
278
268
|
}
|
|
279
269
|
}
|
|
280
270
|
catch {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type UserConfigOption } from './userConfig';
|
|
2
|
+
export interface PluginResolvedConfig {
|
|
3
|
+
options: UserConfigOption[];
|
|
4
|
+
values: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
/** pluginHooks + each handler's resolved NEXRALL_PLUGIN_OPTION_* env map. */
|
|
7
|
+
export declare function resolvePluginHooks(workDir: string): Record<string, unknown[]>;
|
|
8
|
+
/** pluginMcpServers + `${user_config.KEY}` substitution (sensitive included). */
|
|
9
|
+
export declare function resolvePluginMcpServers(workDir: string): Record<string, unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* The resolved config of the plugin a skill DIRECTORY belongs to, or null.
|
|
12
|
+
* Used by skills.ts's expandSkill: a skill under `<plugin>/skills/<name>/` gets
|
|
13
|
+
* its body substituted with that plugin's NON-SENSITIVE values.
|
|
14
|
+
*/
|
|
15
|
+
export declare function pluginConfigForSkillDir(workDir: string, skillDir: string): PluginResolvedConfig | null;
|
|
16
|
+
/** Substitute one text with a plugin's values, non-sensitive only (skill bodies). */
|
|
17
|
+
export declare function substituteSkillBody(text: string, cfg: PluginResolvedConfig): string;
|
|
18
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/plugins/resolve.ts"],"names":[],"mappings":"AAsBA,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AAGtB,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAcD,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CA2B7E;AAED,iFAAiF;AACjF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQhF;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAgBtG;AAED,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,oBAAoB,GAAG,MAAM,CAEnF"}
|