@epoch-agent/core 0.21.0 → 0.23.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/dist/index.d.ts +258 -16
- package/dist/index.js +981 -671
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, statSync, readdirSync, readFileSync, mkdirSync, writeFileSy
|
|
|
2
2
|
import { homedir, platform, tmpdir, hostname } from 'os';
|
|
3
3
|
import { join, dirname, resolve, relative, isAbsolute, sep, extname, basename } from 'path';
|
|
4
4
|
import { execFile, execSync, execFileSync, spawn } from 'child_process';
|
|
5
|
-
import { createLogger, dbPath, resolveHomeDir, DEFAULT_MAX_TURNS, PROJECT_DIR_NAME, guardSpawn, t, suggestKey, misspelledKeyIssues, openDatabase, migrate, releaseDatabase, parseLenient, issueDetails, splitWords, unknownKeyIssues, checkpointsDir, pluginsDir, projectHooksPath, projectClaudeSettingsPath, projectClaudeLocalSettingsPath, projectSettingsPath, projectLocalSettingsPath, projectPoliciesDir, trustedImportsPath, canProbeGit, budgetStatePath, artifactsDir, UNLIMITED_TURNS, turnLimitOf, configPath, managedSettingsPath, getSecretValues, listStoredSecretNames, maskApiKey, setSectionField, countCodePoints, headCodePoints, attachmentsDir,
|
|
5
|
+
import { createLogger, dbPath, resolveHomeDir, DEFAULT_MAX_TURNS, PROJECT_DIR_NAME, guardSpawn, t, suggestKey, misspelledKeyIssues, openDatabase, migrate, releaseDatabase, parseLenient, issueDetails, splitWords, unknownKeyIssues, checkpointsDir, expandPath, pluginsDir, projectHooksPath, projectClaudeSettingsPath, projectClaudeLocalSettingsPath, projectSettingsPath, projectLocalSettingsPath, projectPoliciesDir, trustedImportsPath, canProbeGit, budgetStatePath, artifactsDir, isInWorkspace, UNLIMITED_TURNS, turnLimitOf, configPath, managedSettingsPath, getSecretValues, listStoredSecretNames, maskApiKey, setSectionField, countCodePoints, headCodePoints, attachmentsDir, workspacesPath, samePath, lastSessionsPath, appearancePath, automationLogsDir, projectComplianceDir, projectSkillsDir, trustPath, projectCommandsDir, detectBackend, EXEC_PATH_AS_NODE_ENV, isolate, createStreamDecoder, parseShellCommand, writeArtifact, envPath, checkDangerousCommand, checkObfuscation, keepHeadAndTail, normalizeForMatch, isReadOnlyCommand, CODE_EXEC_ROOTS, tailCodePoints } from '@epoch-agent/infra';
|
|
6
6
|
export { IS_WINDOWS, WINDOWS_HIDE_FLAGS, buildBwrapArgs, buildProfile, checkDangerousCommand, checkObfuscation, createLogger, detectBackend, getDefaultShell, getPythonCommand, isInWorkspace, isReadOnlyCommand, isolate, maskApiKey, probeBubblewrap, probeSeatbelt, complianceDir as resolveComplianceDir, policiesDir as resolvePoliciesDir, setLogLevel } from '@epoch-agent/infra';
|
|
7
7
|
import { PROVIDER_TYPES, OPERATION_TYPES as OPERATION_TYPES$1, COMPLIANCE_CATEGORIES, COMPLIANCE_ACTIONS, SEARCH_PROVIDER_TYPES, CURRENCIES, LANGS, isSettingsPaneId, SETTINGS_PANE_IDS, PERMISSION_LEVELS, SHELL_KINDS, ToolExposure, MAX_OPTIONS, MIN_OPTIONS, MAX_HEADER_CHARS, MAX_QUESTIONS, SCHEDULE_INTERVAL_MINUTES, isPermissionLevel, SCHEDULE_DRAFT_TOOL, isValidAgentRoleName, DEFAULT_AGENT_ROLE, isValidCommandName, RESERVED_COMMAND_NAMES, parseModelRef, isWirePluginArchiveName, systemNote, formatMoney, totalUsageTokens, NOOP_TELEMETRY, METRIC, contentToText, GEN_AI, isPromptOversize, promptTokens, apiKeyEnvVar, PROVIDER_INFOS, isProviderType, API_KEY_ENV_VARS, KEY_ACTIONS, tableOf, perAction, isKeyAction, parseSequence, RESERVED_CHORDS, chordId, sequenceId, ACTION_CONTEXTS, SEQUENCE_CONTEXTS, assertNeverPart, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_REFS, utf8ByteLength, truncateToBudget, attachSessionSurface, isContextNearlyFull, isOperationType, normalizeApproval, imagePartOmittedSummary, MAX_ATTACH_BYTES, SIMULTANEOUS_CONTEXTS, SESSION_REFERENCE_ERROR_CODES, filePartSummary, sessionPartSummary } from '@epoch-agent/protocol';
|
|
8
8
|
export { API_KEY_ENV_VARS, COMPLIANCE_ACTIONS, COMPLIANCE_CATEGORIES, MAX_ATTACH_BYTES, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_ATTACH_BYTES, MAX_SESSION_REFS, OPERATION_TYPES, PERMISSION_LEVELS, PLAN_OUTCOMES, PROVIDER_INFOS, PROVIDER_TYPES, ToolExposure, apiKeyEnvVar, extractAllMentions, extractMentions, extractSessionMentions, getProviderInfo, isOperationType, isPermissionLevel, isPlanOutcome, isProviderType, normalizeApproval } from '@epoch-agent/protocol';
|
|
@@ -487,7 +487,7 @@ function intervalSlots(everyMinutes) {
|
|
|
487
487
|
var runCommand2;
|
|
488
488
|
var init_backend = __esm({
|
|
489
489
|
"src/schedule/os/backend.ts"() {
|
|
490
|
-
runCommand2 = (file, args) => new Promise((
|
|
490
|
+
runCommand2 = (file, args) => new Promise((resolve17) => {
|
|
491
491
|
guardSpawn(
|
|
492
492
|
() => execFile(
|
|
493
493
|
file,
|
|
@@ -495,10 +495,10 @@ var init_backend = __esm({
|
|
|
495
495
|
{ encoding: "buffer", windowsHide: true },
|
|
496
496
|
(err, stdout, stderr) => {
|
|
497
497
|
const code = err && typeof err.code === "number" ? err.code ?? 1 : err ? 1 : 0;
|
|
498
|
-
|
|
498
|
+
resolve17({ code, stdout: decodeOutput(stdout), stderr: decodeOutput(stderr) });
|
|
499
499
|
}
|
|
500
500
|
),
|
|
501
|
-
(err) =>
|
|
501
|
+
(err) => resolve17({ code: 1, stdout: "", stderr: `${file}: ${err.message}` })
|
|
502
502
|
);
|
|
503
503
|
});
|
|
504
504
|
}
|
|
@@ -2065,7 +2065,7 @@ async function runCode(input) {
|
|
|
2065
2065
|
let toolCalls = 0;
|
|
2066
2066
|
let capped2 = false;
|
|
2067
2067
|
let ending = null;
|
|
2068
|
-
return await new Promise((
|
|
2068
|
+
return await new Promise((resolve17) => {
|
|
2069
2069
|
let settled = false;
|
|
2070
2070
|
const finish = () => {
|
|
2071
2071
|
if (settled) return;
|
|
@@ -2074,7 +2074,7 @@ async function runCode(input) {
|
|
|
2074
2074
|
clearInterval(abortWatch);
|
|
2075
2075
|
void worker.terminate().catch(() => {
|
|
2076
2076
|
}).then(() => Promise.race([drained, delay(STREAM_DRAIN_MS)])).then(() => {
|
|
2077
|
-
|
|
2077
|
+
resolve17(toOutcome(ending, { printed, toolCalls, capped: capped2, limits}));
|
|
2078
2078
|
});
|
|
2079
2079
|
};
|
|
2080
2080
|
const timer = setTimeout(() => {
|
|
@@ -2145,14 +2145,14 @@ async function runCode(input) {
|
|
|
2145
2145
|
var ABORT_POLL_MS = 100;
|
|
2146
2146
|
var STREAM_DRAIN_MS = 500;
|
|
2147
2147
|
function streamEnd(stream) {
|
|
2148
|
-
return new Promise((
|
|
2149
|
-
stream.once("end", () =>
|
|
2150
|
-
stream.once("close", () =>
|
|
2148
|
+
return new Promise((resolve17) => {
|
|
2149
|
+
stream.once("end", () => resolve17());
|
|
2150
|
+
stream.once("close", () => resolve17());
|
|
2151
2151
|
});
|
|
2152
2152
|
}
|
|
2153
2153
|
function delay(ms) {
|
|
2154
|
-
return new Promise((
|
|
2155
|
-
setTimeout(
|
|
2154
|
+
return new Promise((resolve17) => {
|
|
2155
|
+
setTimeout(resolve17, ms).unref();
|
|
2156
2156
|
});
|
|
2157
2157
|
}
|
|
2158
2158
|
function timeoutMessage(timeoutMs, toolCalls) {
|
|
@@ -5287,6 +5287,7 @@ var PROJECT_AGENTS_SUBDIR = join(".epoch", "agents");
|
|
|
5287
5287
|
var AGENT_ROLE_DIAG_MODULE = "AgentRole";
|
|
5288
5288
|
var ROLE_FRONTMATTER_SCHEMA = z.object({
|
|
5289
5289
|
name: z.string().min(1).optional(),
|
|
5290
|
+
displayName: z.string().min(1).optional(),
|
|
5290
5291
|
description: z.string().min(1),
|
|
5291
5292
|
tools: z.array(z.string().min(1)).optional(),
|
|
5292
5293
|
skills: z.array(z.string().min(1)).optional(),
|
|
@@ -5361,6 +5362,7 @@ function parseRoleDefinition(raw, file, source) {
|
|
|
5361
5362
|
return {
|
|
5362
5363
|
role: {
|
|
5363
5364
|
name,
|
|
5365
|
+
...fm.displayName ? { displayName: fm.displayName } : {},
|
|
5364
5366
|
description: fm.description,
|
|
5365
5367
|
...prompt ? { prompt } : {},
|
|
5366
5368
|
...fm.tools ? { tools: fm.tools } : {},
|
|
@@ -5463,8 +5465,17 @@ var BUILTIN_ROLES = [
|
|
|
5463
5465
|
source: "builtin"
|
|
5464
5466
|
}
|
|
5465
5467
|
];
|
|
5468
|
+
var BUILTIN_DISPLAY_NAME_KEYS = {
|
|
5469
|
+
[DEFAULT_AGENT_ROLE]: "agent_role.display_general",
|
|
5470
|
+
explore: "agent_role.display_explore",
|
|
5471
|
+
review: "agent_role.display_review"
|
|
5472
|
+
};
|
|
5466
5473
|
function builtinRoles() {
|
|
5467
|
-
return BUILTIN_ROLES.map((
|
|
5474
|
+
return BUILTIN_ROLES.map((role) => {
|
|
5475
|
+
const copied = cloneRole(role);
|
|
5476
|
+
const key = BUILTIN_DISPLAY_NAME_KEYS[role.name];
|
|
5477
|
+
return key ? { ...copied, displayName: t(key) } : copied;
|
|
5478
|
+
});
|
|
5468
5479
|
}
|
|
5469
5480
|
function cloneRole(role) {
|
|
5470
5481
|
return {
|
|
@@ -5490,6 +5501,7 @@ function mergeRoles(overrides) {
|
|
|
5490
5501
|
merged.set(incoming.name, {
|
|
5491
5502
|
...existing,
|
|
5492
5503
|
...incoming.description ? { description: incoming.description } : {},
|
|
5504
|
+
...incoming.displayName ? { displayName: incoming.displayName } : {},
|
|
5493
5505
|
...incoming.prompt ? { prompt: incoming.prompt } : {},
|
|
5494
5506
|
...incoming.maxTurns !== void 0 ? { maxTurns: incoming.maxTurns } : {},
|
|
5495
5507
|
...tools ? { tools } : {},
|
|
@@ -5569,9 +5581,15 @@ function createRoleFile(input, opts) {
|
|
|
5569
5581
|
}
|
|
5570
5582
|
return { ok: true, path, role: back.role };
|
|
5571
5583
|
}
|
|
5584
|
+
function displayNameOf(value) {
|
|
5585
|
+
const trimmed = value?.trim();
|
|
5586
|
+
return trimmed ? trimmed : void 0;
|
|
5587
|
+
}
|
|
5572
5588
|
function frontmatterOf(name, input) {
|
|
5589
|
+
const displayName = displayNameOf(input.displayName);
|
|
5573
5590
|
return {
|
|
5574
5591
|
name,
|
|
5592
|
+
...displayName ? { displayName } : {},
|
|
5575
5593
|
description: input.description.trim(),
|
|
5576
5594
|
...input.tools === void 0 ? {} : { tools: [...input.tools] },
|
|
5577
5595
|
...input.skills === void 0 ? {} : { skills: [...input.skills] },
|
|
@@ -5588,6 +5606,8 @@ ${body2}${body2 ? "\n" : ""}`;
|
|
|
5588
5606
|
}
|
|
5589
5607
|
function driftOf(role, name, input) {
|
|
5590
5608
|
if (role.name !== name) return `name: ${role.name} \u2260 ${name}`;
|
|
5609
|
+
if ((role.displayName ?? null) !== (displayNameOf(input.displayName) ?? null))
|
|
5610
|
+
return "displayName";
|
|
5591
5611
|
if (role.description !== input.description.trim()) return "description";
|
|
5592
5612
|
if ((role.prompt ?? "") !== (input.prompt ?? "").trim()) return "prompt";
|
|
5593
5613
|
const tools = input.tools === void 0 ? void 0 : [...input.tools];
|
|
@@ -6296,6 +6316,7 @@ var ManifestSchema = z.object({
|
|
|
6296
6316
|
epochVersion: z.string().min(1).optional(),
|
|
6297
6317
|
homepage: z.string().min(1).optional(),
|
|
6298
6318
|
keywords: z.array(z.string().min(1)).optional(),
|
|
6319
|
+
dependencies: z.array(z.string().min(1)).optional().catch(void 0),
|
|
6299
6320
|
displayName: z.string().min(1).optional(),
|
|
6300
6321
|
category: z.string().min(1).optional(),
|
|
6301
6322
|
icon: z.string().min(1).optional(),
|
|
@@ -6338,6 +6359,23 @@ function readPluginManifest(dir) {
|
|
|
6338
6359
|
})
|
|
6339
6360
|
});
|
|
6340
6361
|
}
|
|
6362
|
+
const rawDependencies = parsed?.dependencies;
|
|
6363
|
+
if (rawDependencies !== void 0 && !Array.isArray(rawDependencies)) {
|
|
6364
|
+
issues.push({
|
|
6365
|
+
path: `${path}.dependencies`,
|
|
6366
|
+
message: t("plugin_manifest.bad_dependencies", { raw: JSON.stringify(rawDependencies) })
|
|
6367
|
+
});
|
|
6368
|
+
}
|
|
6369
|
+
if (Array.isArray(rawDependencies)) {
|
|
6370
|
+
for (const item of rawDependencies) {
|
|
6371
|
+
if (typeof item !== "string" || !isValidPluginName(item)) {
|
|
6372
|
+
issues.push({
|
|
6373
|
+
path: `${path}.dependencies`,
|
|
6374
|
+
message: t("plugin_manifest.bad_dependency_name", { name: String(item) })
|
|
6375
|
+
});
|
|
6376
|
+
}
|
|
6377
|
+
}
|
|
6378
|
+
}
|
|
6341
6379
|
const checked = parseLenient(ManifestSchema.optional(), parsed, void 0);
|
|
6342
6380
|
if (!checked.value) {
|
|
6343
6381
|
issues.push(
|
|
@@ -6617,7 +6655,7 @@ var PluginStore = class {
|
|
|
6617
6655
|
}
|
|
6618
6656
|
};
|
|
6619
6657
|
function sleep(ms) {
|
|
6620
|
-
return new Promise((
|
|
6658
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
6621
6659
|
}
|
|
6622
6660
|
// src/plugin/loader.ts
|
|
6623
6661
|
var MODULE = "Plugin";
|
|
@@ -6639,6 +6677,7 @@ function loadPlugins(opts) {
|
|
|
6639
6677
|
const state = readPluginRecords(statePath);
|
|
6640
6678
|
const out = noPlugins();
|
|
6641
6679
|
out.issues.push(...state.issues);
|
|
6680
|
+
const declared = /* @__PURE__ */ new Map();
|
|
6642
6681
|
const epochVersion = opts.epochVersion ?? currentEpochVersion();
|
|
6643
6682
|
for (const record of state.records) {
|
|
6644
6683
|
const outcome = admit(record, epochVersion);
|
|
@@ -6657,6 +6696,21 @@ function loadPlugins(opts) {
|
|
|
6657
6696
|
continue;
|
|
6658
6697
|
}
|
|
6659
6698
|
collect(record, out);
|
|
6699
|
+
if (outcome.manifest?.dependencies?.length) {
|
|
6700
|
+
declared.set(record.name, outcome.manifest.dependencies);
|
|
6701
|
+
}
|
|
6702
|
+
}
|
|
6703
|
+
const present = new Set(out.loaded.map((plugin) => plugin.name));
|
|
6704
|
+
for (const [name, dependencies] of declared) {
|
|
6705
|
+
if (!present.has(name)) continue;
|
|
6706
|
+
for (const dependency of dependencies) {
|
|
6707
|
+
if (present.has(dependency)) continue;
|
|
6708
|
+
diags?.warn(
|
|
6709
|
+
MODULE,
|
|
6710
|
+
t("plugin_load.dependency_missing", { name, dependency }),
|
|
6711
|
+
"plugin-dependency-missing"
|
|
6712
|
+
);
|
|
6713
|
+
}
|
|
6660
6714
|
}
|
|
6661
6715
|
for (const detail of issueDetails(out.issues)) {
|
|
6662
6716
|
diags?.warn(MODULE, detail, "plugin-invalid");
|
|
@@ -6683,7 +6737,7 @@ function admit(record, epochVersion) {
|
|
|
6683
6737
|
if (!version.ok) {
|
|
6684
6738
|
return { reason: version.reason, code: "plugin-version-mismatch" };
|
|
6685
6739
|
}
|
|
6686
|
-
return {};
|
|
6740
|
+
return { manifest: manifest.manifest };
|
|
6687
6741
|
}
|
|
6688
6742
|
function collect(record, out) {
|
|
6689
6743
|
const { name, path: dir } = record;
|
|
@@ -7029,708 +7083,887 @@ function firstLine3(err) {
|
|
|
7029
7083
|
const message = err instanceof Error ? err.message : String(err);
|
|
7030
7084
|
return message.split("\n")[0] ?? message;
|
|
7031
7085
|
}
|
|
7032
|
-
var
|
|
7033
|
-
var
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
}
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
const
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
function isArchiveUrl(url) {
|
|
7088
|
-
return isWirePluginArchiveName(url);
|
|
7086
|
+
var MARKETPLACE_FILE = "epoch-marketplace.json";
|
|
7087
|
+
var NAME_PATTERN = PLUGIN_NAME_PATTERN;
|
|
7088
|
+
var EntryCategoryInput = z.union([z.string().min(1), z.array(z.string().min(1))]).optional().catch(void 0);
|
|
7089
|
+
var EntryShape = z.object({
|
|
7090
|
+
name: z.string().regex(NAME_PATTERN),
|
|
7091
|
+
description: z.string().min(1).optional(),
|
|
7092
|
+
source: z.string().min(1),
|
|
7093
|
+
category: EntryCategoryInput,
|
|
7094
|
+
keywords: z.array(z.string().min(1)).optional(),
|
|
7095
|
+
author: PluginAuthorSchema.optional(),
|
|
7096
|
+
downloads: z.number().int().nonnegative().optional(),
|
|
7097
|
+
likes: z.number().int().nonnegative().optional(),
|
|
7098
|
+
displayName: z.string().min(1).optional(),
|
|
7099
|
+
icon: z.string().min(1).optional(),
|
|
7100
|
+
version: z.string().min(1).optional(),
|
|
7101
|
+
changelog: z.string().min(1).optional(),
|
|
7102
|
+
size: z.number().int().positive().optional(),
|
|
7103
|
+
homepage: z.string().min(1).optional(),
|
|
7104
|
+
visibility: z.enum(PLUGIN_VISIBILITY).optional().catch(void 0),
|
|
7105
|
+
status: z.enum(["listed", "reviewing", "rejected", "offline"]).optional().catch(void 0)
|
|
7106
|
+
});
|
|
7107
|
+
var EntrySchema = EntryShape.transform(({ category, ...rest }) => {
|
|
7108
|
+
const picked = category === void 0 ? [] : typeof category === "string" ? [category] : category;
|
|
7109
|
+
return { ...rest, ...picked.length === 0 ? {} : { category: [...picked] } };
|
|
7110
|
+
});
|
|
7111
|
+
var MARKETPLACE_DISPLAY_FIELDS = [
|
|
7112
|
+
"status",
|
|
7113
|
+
"downloads",
|
|
7114
|
+
"likes",
|
|
7115
|
+
"author",
|
|
7116
|
+
"category",
|
|
7117
|
+
"visibility",
|
|
7118
|
+
"icon",
|
|
7119
|
+
"homepage",
|
|
7120
|
+
"size"
|
|
7121
|
+
];
|
|
7122
|
+
var DisplaySchema = z.object({
|
|
7123
|
+
fields: z.array(z.string().min(1)).optional()
|
|
7124
|
+
});
|
|
7125
|
+
var CategoryNodeSchema = z.lazy(
|
|
7126
|
+
() => z.object({
|
|
7127
|
+
id: z.string().min(1),
|
|
7128
|
+
label: z.string().min(1).optional(),
|
|
7129
|
+
children: z.array(CategoryNodeSchema).optional()
|
|
7130
|
+
})
|
|
7131
|
+
);
|
|
7132
|
+
var CategoriesSchema = z.array(CategoryNodeSchema).refine(hasUniqueCategoryIds, { message: "category ids must be unique across the whole tree" }).optional().catch(void 0);
|
|
7133
|
+
function hasUniqueCategoryIds(nodes) {
|
|
7134
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7135
|
+
const walk3 = (list) => list.every((node) => {
|
|
7136
|
+
if (seen.has(node.id)) return false;
|
|
7137
|
+
seen.add(node.id);
|
|
7138
|
+
return node.children === void 0 || walk3(node.children);
|
|
7139
|
+
});
|
|
7140
|
+
return walk3(nodes);
|
|
7089
7141
|
}
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7142
|
+
var CatalogSchema = z.object({
|
|
7143
|
+
name: z.string().regex(NAME_PATTERN),
|
|
7144
|
+
description: z.string().min(1).optional(),
|
|
7145
|
+
owner: z.object({ name: z.string().min(1), url: z.string().min(1).optional() }).optional(),
|
|
7146
|
+
display: DisplaySchema.optional(),
|
|
7147
|
+
categories: CategoriesSchema,
|
|
7148
|
+
plugins: z.array(EntrySchema)
|
|
7149
|
+
});
|
|
7150
|
+
var RecordSchema2 = z.object({
|
|
7151
|
+
name: z.string().regex(NAME_PATTERN),
|
|
7152
|
+
source: z.string().min(1),
|
|
7153
|
+
addedAt: z.number(),
|
|
7154
|
+
catalog: CatalogSchema
|
|
7155
|
+
});
|
|
7156
|
+
var StateSchema2 = z.object({
|
|
7157
|
+
version: z.literal(1).optional(),
|
|
7158
|
+
marketplaces: z.array(RecordSchema2)
|
|
7159
|
+
});
|
|
7160
|
+
function projectEntryForDisplay(entry, display) {
|
|
7161
|
+
const allowed = display?.fields;
|
|
7162
|
+
if (allowed === void 0) return entry;
|
|
7163
|
+
const out = { ...entry };
|
|
7164
|
+
for (const field of MARKETPLACE_DISPLAY_FIELDS) {
|
|
7165
|
+
if (!displayAllows(display, field)) delete out[field];
|
|
7166
|
+
}
|
|
7167
|
+
return out;
|
|
7097
7168
|
}
|
|
7098
|
-
function
|
|
7099
|
-
|
|
7169
|
+
function displayAllows(display, field) {
|
|
7170
|
+
const allowed = display?.fields;
|
|
7171
|
+
if (allowed === void 0) return true;
|
|
7172
|
+
return allowed.includes(field);
|
|
7100
7173
|
}
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7174
|
+
function readMarketplaces(statePath) {
|
|
7175
|
+
if (!existsSync(statePath)) return { records: [], issues: [] };
|
|
7176
|
+
let raw;
|
|
7177
|
+
try {
|
|
7178
|
+
raw = JSON.parse(readFileSync(statePath, "utf-8"));
|
|
7179
|
+
} catch (err) {
|
|
7105
7180
|
return {
|
|
7106
|
-
|
|
7107
|
-
|
|
7181
|
+
records: [],
|
|
7182
|
+
issues: [
|
|
7183
|
+
{ path: statePath, message: t("plugin_marketplace.bad_json", { reason: first(err) }) }
|
|
7184
|
+
]
|
|
7108
7185
|
};
|
|
7109
7186
|
}
|
|
7110
|
-
|
|
7111
|
-
|
|
7187
|
+
const checked = parseLenient(StateSchema2.optional(), raw, void 0);
|
|
7188
|
+
if (!checked.value) {
|
|
7189
|
+
return {
|
|
7190
|
+
records: [],
|
|
7191
|
+
issues: checked.issues.map((i) => ({
|
|
7192
|
+
path: statePath,
|
|
7193
|
+
message: t("plugin_marketplace.issue", { path: i.path, message: i.message })
|
|
7194
|
+
}))
|
|
7195
|
+
};
|
|
7196
|
+
}
|
|
7197
|
+
return { records: checked.value.marketplaces, issues: [] };
|
|
7198
|
+
}
|
|
7199
|
+
async function mutate(statePath, fn) {
|
|
7200
|
+
const release = await acquireStateLock(statePath);
|
|
7112
7201
|
try {
|
|
7113
|
-
|
|
7202
|
+
const next = fn(readMarketplaces(statePath).records);
|
|
7203
|
+
if (!next) return false;
|
|
7204
|
+
writeStateFile(statePath, JSON.stringify({ version: 1, marketplaces: next }, null, 2));
|
|
7205
|
+
return true;
|
|
7114
7206
|
} finally {
|
|
7115
|
-
|
|
7207
|
+
release();
|
|
7116
7208
|
}
|
|
7117
7209
|
}
|
|
7118
|
-
async function
|
|
7119
|
-
const fetched = await
|
|
7120
|
-
if (!fetched.ok) return
|
|
7121
|
-
const
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
return { ok: false, reason: t("plugin_install.manifest_unusable", { detail: `
|
|
7127
|
-
${detail}` }) };
|
|
7128
|
-
}
|
|
7129
|
-
const taken = new PluginStore(opts.statePath).read().records.find((r) => r.name === manifest.name);
|
|
7130
|
-
const conflict = taken && taken.name !== opts.replace ? taken : void 0;
|
|
7131
|
-
const current = opts.epochVersion ?? currentEpochVersion();
|
|
7132
|
-
const version = checkEpochVersion(manifest.epochVersion, current);
|
|
7133
|
-
const versionUnmet = !version.ok && manifest.epochVersion ? { required: manifest.epochVersion, current, reason: version.reason } : void 0;
|
|
7134
|
-
const preview3 = {
|
|
7135
|
-
manifest,
|
|
7136
|
-
source: resolved,
|
|
7137
|
-
inventory: scanPluginDir(readDir, manifest.name),
|
|
7138
|
-
...conflict ? { conflict } : {},
|
|
7139
|
-
...versionUnmet ? { versionUnmet } : {}
|
|
7210
|
+
async function addMarketplace(source, opts) {
|
|
7211
|
+
const fetched = await fetchCatalog(source);
|
|
7212
|
+
if (!fetched.ok) return fetched;
|
|
7213
|
+
const record = {
|
|
7214
|
+
name: fetched.catalog.name,
|
|
7215
|
+
source: source.trim(),
|
|
7216
|
+
addedAt: Date.now(),
|
|
7217
|
+
catalog: fetched.catalog
|
|
7140
7218
|
};
|
|
7141
|
-
|
|
7219
|
+
const written = await mutate(
|
|
7220
|
+
opts.statePath,
|
|
7221
|
+
(records) => records.some((r) => r.name === record.name) ? void 0 : [...records, record].sort((a, b) => a.name.localeCompare(b.name))
|
|
7222
|
+
);
|
|
7223
|
+
return written ? { ok: true, record } : {
|
|
7224
|
+
ok: false,
|
|
7225
|
+
reason: t("plugin_marketplace.already_added", { name: record.name })
|
|
7226
|
+
};
|
|
7227
|
+
}
|
|
7228
|
+
async function removeMarketplace(name, opts) {
|
|
7229
|
+
const written = await mutate(
|
|
7230
|
+
opts.statePath,
|
|
7231
|
+
(records) => records.some((r) => r.name === name) ? records.filter((r) => r.name !== name) : void 0
|
|
7232
|
+
);
|
|
7233
|
+
return written ? { ok: true } : { ok: false, reason: t("plugin_marketplace.not_added", { name }) };
|
|
7234
|
+
}
|
|
7235
|
+
async function updateMarketplace(name, opts) {
|
|
7236
|
+
const existing = readMarketplaces(opts.statePath).records.find((r) => r.name === name);
|
|
7237
|
+
if (!existing) return { ok: false, reason: t("plugin_marketplace.not_added", { name }) };
|
|
7238
|
+
const fetched = await fetchCatalog(existing.source);
|
|
7239
|
+
if (!fetched.ok) return fetched;
|
|
7240
|
+
if (fetched.catalog.name !== name) {
|
|
7142
7241
|
return {
|
|
7143
7242
|
ok: false,
|
|
7144
|
-
|
|
7145
|
-
|
|
7243
|
+
reason: t("plugin_marketplace.renamed", {
|
|
7244
|
+
source: existing.source,
|
|
7245
|
+
name: fetched.catalog.name
|
|
7246
|
+
})
|
|
7146
7247
|
};
|
|
7147
7248
|
}
|
|
7148
|
-
|
|
7249
|
+
const record = { ...existing, catalog: fetched.catalog };
|
|
7250
|
+
await mutate(opts.statePath, (records) => records.map((r) => r.name === name ? record : r));
|
|
7251
|
+
return { ok: true, record };
|
|
7252
|
+
}
|
|
7253
|
+
function searchMarketplaces(keyword, statePath) {
|
|
7254
|
+
const needle = keyword.trim().toLowerCase();
|
|
7255
|
+
const hits = [];
|
|
7256
|
+
for (const record of readMarketplaces(statePath).records) {
|
|
7257
|
+
for (const entry of record.catalog.plugins) {
|
|
7258
|
+
const haystack = [
|
|
7259
|
+
entry.name,
|
|
7260
|
+
entry.description ?? "",
|
|
7261
|
+
...entry.category ?? [],
|
|
7262
|
+
entry.author?.name ?? "",
|
|
7263
|
+
...entry.keywords ?? []
|
|
7264
|
+
].join(" ").toLowerCase();
|
|
7265
|
+
if (needle && !haystack.includes(needle)) continue;
|
|
7266
|
+
hits.push({
|
|
7267
|
+
marketplace: record.name,
|
|
7268
|
+
entry: projectEntryForDisplay(entry, record.catalog.display),
|
|
7269
|
+
ref: `${record.name}/${entry.name}`
|
|
7270
|
+
});
|
|
7271
|
+
}
|
|
7272
|
+
}
|
|
7273
|
+
return hits;
|
|
7274
|
+
}
|
|
7275
|
+
function resolveMarketplaceRef(input, statePath) {
|
|
7276
|
+
const parts = input.trim().split("/");
|
|
7277
|
+
if (parts.length !== 2) return void 0;
|
|
7278
|
+
const [market = "", plugin = ""] = parts;
|
|
7279
|
+
if (!NAME_PATTERN.test(market) || !NAME_PATTERN.test(plugin)) return void 0;
|
|
7280
|
+
const record = readMarketplaces(statePath).records.find((r) => r.name === market);
|
|
7281
|
+
if (!record) {
|
|
7149
7282
|
return {
|
|
7150
7283
|
ok: false,
|
|
7151
|
-
|
|
7152
|
-
reason: t("plugin_install.already_installed", {
|
|
7153
|
-
name: conflict.name,
|
|
7154
|
-
version: conflict.version,
|
|
7155
|
-
source: conflict.source
|
|
7156
|
-
})
|
|
7284
|
+
reason: t("plugin_marketplace.market_not_added", { market, input })
|
|
7157
7285
|
};
|
|
7158
7286
|
}
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
preview: preview3,
|
|
7166
|
-
reason: t("plugin_install.raced", { name: manifest.name })
|
|
7167
|
-
};
|
|
7168
|
-
}
|
|
7169
|
-
async function commit(source, staging, preview3, opts) {
|
|
7170
|
-
const name = preview3.manifest.name;
|
|
7171
|
-
const dest = join(opts.pluginsDir, name);
|
|
7172
|
-
removeInstallDest(dest);
|
|
7173
|
-
const linked = source.type === "local";
|
|
7174
|
-
if (linked) {
|
|
7175
|
-
try {
|
|
7176
|
-
symlinkSync(source.target, dest, "junction");
|
|
7177
|
-
} catch {
|
|
7178
|
-
opts.onProgress?.(t("plugin_install.symlink_failed"));
|
|
7179
|
-
cpSync(source.target, dest, { recursive: true });
|
|
7180
|
-
return write(false);
|
|
7181
|
-
}
|
|
7182
|
-
} else {
|
|
7183
|
-
renameSync(pluginRoot(source, staging), dest);
|
|
7287
|
+
const entry = record.catalog.plugins.find((p) => p.name === plugin);
|
|
7288
|
+
if (!entry) {
|
|
7289
|
+
return {
|
|
7290
|
+
ok: false,
|
|
7291
|
+
reason: t("plugin_marketplace.plugin_not_in_market", { market, plugin })
|
|
7292
|
+
};
|
|
7184
7293
|
}
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
enabled: true,
|
|
7195
|
-
installedAt: Date.now(),
|
|
7196
|
-
...opts.marketplace ? { marketplace: opts.marketplace } : {},
|
|
7197
|
-
...source.sha256 ? { checksum: `sha256:${source.sha256}` } : {}
|
|
7294
|
+
const source = resolveEntrySource(entry.source, record.source);
|
|
7295
|
+
if (!source) {
|
|
7296
|
+
return {
|
|
7297
|
+
ok: false,
|
|
7298
|
+
reason: t("plugin_marketplace.entry_unresolvable", {
|
|
7299
|
+
market,
|
|
7300
|
+
plugin,
|
|
7301
|
+
source: entry.source
|
|
7302
|
+
})
|
|
7198
7303
|
};
|
|
7199
|
-
return new PluginStore(opts.statePath).mutate((records) => {
|
|
7200
|
-
const taken = records.some((r) => r.name === name);
|
|
7201
|
-
if (taken && opts.replace !== name) return void 0;
|
|
7202
|
-
return {
|
|
7203
|
-
records: taken ? records.map((r) => r.name === name ? record : r) : [...records, record],
|
|
7204
|
-
result: record
|
|
7205
|
-
};
|
|
7206
|
-
});
|
|
7207
7304
|
}
|
|
7305
|
+
return { ok: true, ref: { marketplace: market, source } };
|
|
7208
7306
|
}
|
|
7209
|
-
function
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
if (
|
|
7216
|
-
|
|
7217
|
-
|
|
7307
|
+
function resolveEntrySource(entry, marketSource) {
|
|
7308
|
+
const spec = entry.trim();
|
|
7309
|
+
if (!spec.startsWith(".") && !spec.startsWith("/")) return spec;
|
|
7310
|
+
const rel = spec.replace(/^\.\//, "").replace(/^\//, "");
|
|
7311
|
+
if (rel === "" || rel.split("/").includes("..")) return void 0;
|
|
7312
|
+
const market = marketSource.trim();
|
|
7313
|
+
if (market.startsWith("github:") || market.startsWith("git+")) {
|
|
7314
|
+
const [base = "", fragment] = market.split("#", 2);
|
|
7315
|
+
const prefix = fragment?.startsWith("subdir=") ? `${fragment.slice("subdir=".length)}/` : "";
|
|
7316
|
+
return `${base}#subdir=${prefix}${rel}`;
|
|
7218
7317
|
}
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
} catch {
|
|
7222
|
-
rmdirSync(dest);
|
|
7318
|
+
if (market.startsWith("https://") || market.startsWith("http://")) {
|
|
7319
|
+
return `${market.replace(/\/[^/]*$/, "")}/${rel}`;
|
|
7223
7320
|
}
|
|
7321
|
+
return join(marketDir(market), rel);
|
|
7224
7322
|
}
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
}
|
|
7233
|
-
async function fetchLocalArchive(source, staging) {
|
|
7234
|
-
if (!existsSync(source.target)) {
|
|
7235
|
-
return { ok: false, reason: t("plugin_install.archive_missing", { path: source.target }) };
|
|
7323
|
+
function findMarketplaceEntryByName(name, statePath) {
|
|
7324
|
+
for (const record of readMarketplaces(statePath).records) {
|
|
7325
|
+
const entry = record.catalog.plugins.find((plugin) => plugin.name === name);
|
|
7326
|
+
if (!entry) continue;
|
|
7327
|
+
const source = resolveEntrySource(entry.source, record.source);
|
|
7328
|
+
if (!source) continue;
|
|
7329
|
+
return { marketplace: record.name, source };
|
|
7236
7330
|
}
|
|
7237
|
-
|
|
7238
|
-
return extractArchive(source.target, staging);
|
|
7331
|
+
return void 0;
|
|
7239
7332
|
}
|
|
7240
|
-
async function
|
|
7241
|
-
const
|
|
7242
|
-
if (!
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
let answer;
|
|
7333
|
+
async function fetchCatalog(source) {
|
|
7334
|
+
const input = source.trim();
|
|
7335
|
+
if (!input) return { ok: false, reason: t("plugin_marketplace.source_empty") };
|
|
7336
|
+
const local = localCatalogPath(input);
|
|
7337
|
+
if (local) {
|
|
7338
|
+
if (!existsSync(local)) {
|
|
7339
|
+
return { ok: false, reason: t("plugin_marketplace.local_missing", { path: local }) };
|
|
7340
|
+
}
|
|
7249
7341
|
try {
|
|
7250
|
-
|
|
7342
|
+
return parseCatalog(readFileSync(local, "utf-8"), local);
|
|
7251
7343
|
} catch (err) {
|
|
7252
|
-
return {
|
|
7253
|
-
ok: false,
|
|
7254
|
-
reason: t("plugin_install.host_fetch_threw", {
|
|
7255
|
-
reason: (err instanceof Error ? err.message : String(err)).split("\n")[0] ?? ""
|
|
7256
|
-
})
|
|
7257
|
-
};
|
|
7258
|
-
}
|
|
7259
|
-
if (!answer.ok) {
|
|
7260
|
-
return {
|
|
7261
|
-
ok: false,
|
|
7262
|
-
reason: answer.reason ?? t("plugin_install.host_fetch_failed", { target: source.target })
|
|
7263
|
-
};
|
|
7344
|
+
return { ok: false, reason: t("plugin_marketplace.read_failed", { reason: first(err) }) };
|
|
7264
7345
|
}
|
|
7265
|
-
|
|
7346
|
+
}
|
|
7347
|
+
const url = catalogUrl(input);
|
|
7348
|
+
if (!url) {
|
|
7349
|
+
return {
|
|
7350
|
+
ok: false,
|
|
7351
|
+
reason: t("plugin_marketplace.bad_url", { input, file: MARKETPLACE_FILE })
|
|
7352
|
+
};
|
|
7353
|
+
}
|
|
7354
|
+
try {
|
|
7355
|
+
const response = await fetch(url, { redirect: "follow" });
|
|
7356
|
+
if (!response.ok) {
|
|
7357
|
+
const vars = { url, status: response.status };
|
|
7266
7358
|
return {
|
|
7267
7359
|
ok: false,
|
|
7268
|
-
reason: t("
|
|
7360
|
+
reason: looksPrivate(response.status) ? t("marketplace.fetch_failed_private", vars) : t("marketplace.fetch_failed", vars)
|
|
7269
7361
|
};
|
|
7270
7362
|
}
|
|
7271
|
-
return
|
|
7272
|
-
})
|
|
7273
|
-
}
|
|
7274
|
-
function fetchLocal(source) {
|
|
7275
|
-
if (!existsSync(source.target)) {
|
|
7276
|
-
return { ok: false, reason: t("plugin_install.local_missing", { path: source.target }) };
|
|
7363
|
+
return parseCatalog(await response.text(), url);
|
|
7364
|
+
} catch (err) {
|
|
7365
|
+
return { ok: false, reason: t("marketplace.fetch_error", { url, reason: first(err) }) };
|
|
7277
7366
|
}
|
|
7278
|
-
return { ok: true };
|
|
7279
7367
|
}
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7368
|
+
function looksPrivate(status) {
|
|
7369
|
+
return status === 401 || status === 403 || status === 404;
|
|
7370
|
+
}
|
|
7371
|
+
function catalogUrl(input) {
|
|
7372
|
+
if (input.startsWith("github:")) {
|
|
7373
|
+
const slug = input.slice("github:".length);
|
|
7374
|
+
if (!/^[\w.-]+\/[\w.-]+$/.test(slug)) return void 0;
|
|
7375
|
+
return `https://raw.githubusercontent.com/${slug}/HEAD/${MARKETPLACE_FILE}`;
|
|
7285
7376
|
}
|
|
7286
|
-
|
|
7287
|
-
return
|
|
7377
|
+
if (!input.startsWith("https://") && !input.startsWith("http://")) return void 0;
|
|
7378
|
+
return input.endsWith(".json") ? input : `${input.replace(/\/+$/, "")}/${MARKETPLACE_FILE}`;
|
|
7288
7379
|
}
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
"npm",
|
|
7295
|
-
["pack", source.target, "--pack-destination", dl, "--silent"],
|
|
7296
|
-
{ cwd: dl, windowsShell: true }
|
|
7297
|
-
);
|
|
7298
|
-
if (!packed.ok) {
|
|
7299
|
-
return { ok: false, reason: t("plugin_install.npm_pack_failed", { detail: packed.detail }) };
|
|
7300
|
-
}
|
|
7301
|
-
const tarball = packed.stdout.trim().split("\n").pop()?.trim();
|
|
7302
|
-
if (!tarball) return { ok: false, reason: t("plugin_install.npm_no_tarball") };
|
|
7303
|
-
return extractArchive(isAbsolute(tarball) ? tarball : join(dl, tarball), staging);
|
|
7304
|
-
});
|
|
7380
|
+
function localCatalogPath(input) {
|
|
7381
|
+
if (/^[a-z][a-z0-9+.-]+:/i.test(input) || input.startsWith("//")) return void 0;
|
|
7382
|
+
const abs = isAbsolute(input) ? input : resolve(input);
|
|
7383
|
+
if (existsSync(abs) && statSync(abs).isDirectory()) return join(abs, MARKETPLACE_FILE);
|
|
7384
|
+
return abs;
|
|
7305
7385
|
}
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7386
|
+
function marketDir(market) {
|
|
7387
|
+
const abs = isAbsolute(market) ? market : resolve(market);
|
|
7388
|
+
if (existsSync(abs) && statSync(abs).isDirectory()) return abs;
|
|
7389
|
+
return abs.replace(/[/\\][^/\\]*$/, "");
|
|
7390
|
+
}
|
|
7391
|
+
function parseCatalog(body2, where) {
|
|
7392
|
+
let raw;
|
|
7310
7393
|
try {
|
|
7311
|
-
|
|
7312
|
-
if (!response.ok) {
|
|
7313
|
-
return {
|
|
7314
|
-
ok: false,
|
|
7315
|
-
reason: t("plugin_install.download_http", {
|
|
7316
|
-
status: response.status,
|
|
7317
|
-
statusText: response.statusText
|
|
7318
|
-
})
|
|
7319
|
-
};
|
|
7320
|
-
}
|
|
7321
|
-
bytes = Buffer.from(await response.arrayBuffer());
|
|
7394
|
+
raw = JSON.parse(body2);
|
|
7322
7395
|
} catch (err) {
|
|
7323
7396
|
return {
|
|
7324
7397
|
ok: false,
|
|
7325
|
-
reason: t("
|
|
7326
|
-
message: err instanceof Error ? err.message : String(err)
|
|
7327
|
-
})
|
|
7398
|
+
reason: t("plugin_marketplace.catalog_bad_json", { where, reason: first(err) })
|
|
7328
7399
|
};
|
|
7329
7400
|
}
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
ok: false,
|
|
7335
|
-
reason: [
|
|
7336
|
-
t("plugin_install.sha_mismatch"),
|
|
7337
|
-
t("plugin_install.sha_expected", { expected: source.sha256 }),
|
|
7338
|
-
t("plugin_install.sha_actual", { actual })
|
|
7339
|
-
].join("\n")
|
|
7340
|
-
};
|
|
7341
|
-
}
|
|
7401
|
+
const checked = parseLenient(CatalogSchema.optional(), raw, void 0);
|
|
7402
|
+
if (!checked.value) {
|
|
7403
|
+
const detail = checked.issues.map((i) => t("plugin_marketplace.issue", { path: i.path, message: i.message })).join(t("plugin_marketplace.catalog_issue_sep"));
|
|
7404
|
+
return { ok: false, reason: t("plugin_marketplace.catalog_invalid", { where, detail }) };
|
|
7342
7405
|
}
|
|
7343
|
-
return
|
|
7344
|
-
const archive = join(dl, `download${archiveExt(source.target)}`);
|
|
7345
|
-
writeFileSync(archive, bytes);
|
|
7346
|
-
return extractArchive(archive, staging);
|
|
7347
|
-
});
|
|
7406
|
+
return { ok: true, catalog: checked.value };
|
|
7348
7407
|
}
|
|
7349
|
-
function
|
|
7350
|
-
const
|
|
7351
|
-
|
|
7352
|
-
if (path.endsWith(".tar.gz")) return ".tar.gz";
|
|
7353
|
-
return ".zip";
|
|
7408
|
+
function first(err) {
|
|
7409
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7410
|
+
return message.split("\n")[0] ?? t("plugin_marketplace.unknown_error");
|
|
7354
7411
|
}
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7412
|
+
var NPM_SPEC = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*(?:@[a-zA-Z0-9.^~*+-]+)?$/;
|
|
7413
|
+
var REMOTE_URL = /^https?:\/\/[^\s'"\\^|<>]+$/;
|
|
7414
|
+
function resolveSource(raw) {
|
|
7415
|
+
const input = raw.trim();
|
|
7416
|
+
if (!input) return void 0;
|
|
7417
|
+
if (input.startsWith("github:")) {
|
|
7418
|
+
const [slug = "", fragment] = input.slice("github:".length).split("#", 2);
|
|
7419
|
+
if (!/^[\w.-]+\/[\w.-]+$/.test(slug)) return void 0;
|
|
7420
|
+
const sub = subdirOf(fragment);
|
|
7421
|
+
if (!sub.ok) return void 0;
|
|
7422
|
+
return {
|
|
7423
|
+
type: "git",
|
|
7424
|
+
raw: input,
|
|
7425
|
+
target: `https://github.com/${slug}.git`,
|
|
7426
|
+
...sub.subdir ? { subdir: sub.subdir } : {}
|
|
7427
|
+
};
|
|
7428
|
+
}
|
|
7429
|
+
if (input.startsWith("git+")) {
|
|
7430
|
+
const [url = "", fragment] = input.slice("git+".length).split("#", 2);
|
|
7431
|
+
if (!REMOTE_URL.test(url)) return void 0;
|
|
7432
|
+
const sub = subdirOf(fragment);
|
|
7433
|
+
if (!sub.ok) return void 0;
|
|
7434
|
+
return { type: "git", raw: input, target: url, ...sub.subdir ? { subdir: sub.subdir } : {} };
|
|
7435
|
+
}
|
|
7436
|
+
if (input.startsWith("npm:")) {
|
|
7437
|
+
const pkg = input.slice("npm:".length);
|
|
7438
|
+
if (!NPM_SPEC.test(pkg)) return void 0;
|
|
7439
|
+
return { type: "npm", raw: input, target: pkg };
|
|
7440
|
+
}
|
|
7441
|
+
if (input.startsWith("host:")) {
|
|
7442
|
+
const opaque = input.slice("host:".length).trim();
|
|
7443
|
+
if (!opaque) return void 0;
|
|
7444
|
+
return { type: "host", raw: input, target: opaque };
|
|
7445
|
+
}
|
|
7446
|
+
if (input.startsWith("https://") || input.startsWith("http://")) {
|
|
7447
|
+
const [url = "", fragment] = input.split("#", 2);
|
|
7448
|
+
if (!REMOTE_URL.test(url)) return void 0;
|
|
7449
|
+
const sha = fragment?.startsWith("sha256=") ? fragment.slice("sha256=".length) : void 0;
|
|
7450
|
+
if (isArchiveUrl(url)) {
|
|
7451
|
+
if (sha !== void 0 && !/^[a-f0-9]{64}$/i.test(sha)) return void 0;
|
|
7452
|
+
return {
|
|
7453
|
+
type: "archive",
|
|
7454
|
+
raw: input,
|
|
7455
|
+
target: url,
|
|
7456
|
+
...sha ? { sha256: sha.toLowerCase() } : {}
|
|
7457
|
+
};
|
|
7458
|
+
}
|
|
7459
|
+
return { type: "git", raw: input, target: url };
|
|
7460
|
+
}
|
|
7461
|
+
const abs = isAbsolute(input) ? input : resolve(input);
|
|
7462
|
+
if (isArchiveUrl(abs)) {
|
|
7463
|
+
return { type: "archive", raw: input, target: abs, localFile: true };
|
|
7361
7464
|
}
|
|
7465
|
+
return { type: "local", raw: input, target: abs };
|
|
7362
7466
|
}
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
var PLUGIN_ROOT_ENV = "EPOCH_PLUGIN_ROOT";
|
|
7366
|
-
function mentionsPluginRoot(text) {
|
|
7367
|
-
return text.includes(PLUGIN_ROOT_TOKEN);
|
|
7467
|
+
function isArchiveUrl(url) {
|
|
7468
|
+
return isWirePluginArchiveName(url);
|
|
7368
7469
|
}
|
|
7369
|
-
function
|
|
7370
|
-
|
|
7470
|
+
function subdirOf(fragment) {
|
|
7471
|
+
if (fragment === void 0 || fragment === "") return { ok: true };
|
|
7472
|
+
if (!fragment.startsWith("subdir=")) return { ok: false };
|
|
7473
|
+
const rel = fragment.slice("subdir=".length).replace(/\/+$/, "");
|
|
7474
|
+
if (!/^[\w.-]+(?:\/[\w.-]+)*$/.test(rel)) return { ok: false };
|
|
7475
|
+
if (rel.split("/").includes("..")) return { ok: false };
|
|
7476
|
+
return { ok: true, subdir: rel };
|
|
7371
7477
|
}
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
const hit = records.find((r) => r.name === name);
|
|
7375
|
-
if (!hit) return void 0;
|
|
7376
|
-
return { records: records.filter((r) => r.name !== name), result: hit };
|
|
7377
|
-
});
|
|
7378
|
-
if (!removed) return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7379
|
-
if (removed.linked) {
|
|
7380
|
-
rmSync(removed.path, { force: true });
|
|
7381
|
-
return { ok: true, message: t("plugin_lifecycle.uninstalled_link", { name }) };
|
|
7382
|
-
}
|
|
7383
|
-
rmSync(removed.path, { recursive: true, force: true });
|
|
7384
|
-
return { ok: true, message: t("plugin_lifecycle.uninstalled", { name }) };
|
|
7478
|
+
function pluginRoot(source, staging) {
|
|
7479
|
+
return source.subdir ? join(staging, source.subdir) : staging;
|
|
7385
7480
|
}
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7481
|
+
// src/plugin/install.ts
|
|
7482
|
+
async function installPlugin(source, opts) {
|
|
7483
|
+
const resolved = resolveSource(source);
|
|
7484
|
+
if (!resolved) {
|
|
7390
7485
|
return {
|
|
7391
|
-
|
|
7392
|
-
|
|
7486
|
+
ok: false,
|
|
7487
|
+
reason: t("plugin_install.bad_source", { source })
|
|
7393
7488
|
};
|
|
7394
|
-
});
|
|
7395
|
-
if (changed === void 0) {
|
|
7396
|
-
return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7397
7489
|
}
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
}
|
|
7403
|
-
}
|
|
7404
|
-
async function updatePlugin(name, opts) {
|
|
7405
|
-
const existing = new PluginStore(opts.statePath).read().records.find((r) => r.name === name);
|
|
7406
|
-
if (!existing) return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7407
|
-
if (existing.linked) {
|
|
7408
|
-
return {
|
|
7409
|
-
ok: true,
|
|
7410
|
-
message: t("plugin_lifecycle.linked_no_update", { name, source: existing.source })
|
|
7411
|
-
};
|
|
7490
|
+
mkdirSync(opts.pluginsDir, { recursive: true });
|
|
7491
|
+
const staging = join(opts.pluginsDir, `.staging-${randomUUID().slice(0, 8)}`);
|
|
7492
|
+
try {
|
|
7493
|
+
return await runInstall(resolved, staging, opts);
|
|
7494
|
+
} finally {
|
|
7495
|
+
rmSync(staging, { recursive: true, force: true });
|
|
7412
7496
|
}
|
|
7413
|
-
return installPlugin(existing.source, {
|
|
7414
|
-
...opts,
|
|
7415
|
-
replace: name,
|
|
7416
|
-
...existing.marketplace ? { marketplace: existing.marketplace } : {}
|
|
7417
|
-
});
|
|
7418
7497
|
}
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
likes: z.number().int().nonnegative().optional(),
|
|
7431
|
-
displayName: z.string().min(1).optional(),
|
|
7432
|
-
icon: z.string().min(1).optional(),
|
|
7433
|
-
version: z.string().min(1).optional(),
|
|
7434
|
-
changelog: z.string().min(1).optional(),
|
|
7435
|
-
size: z.number().int().positive().optional(),
|
|
7436
|
-
homepage: z.string().min(1).optional(),
|
|
7437
|
-
visibility: z.enum(PLUGIN_VISIBILITY).optional().catch(void 0),
|
|
7438
|
-
status: z.enum(["listed", "reviewing", "rejected", "offline"]).optional().catch(void 0)
|
|
7439
|
-
});
|
|
7440
|
-
var EntrySchema = EntryShape.transform(({ category, ...rest }) => {
|
|
7441
|
-
const picked = category === void 0 ? [] : typeof category === "string" ? [category] : category;
|
|
7442
|
-
return { ...rest, ...picked.length === 0 ? {} : { category: [...picked] } };
|
|
7443
|
-
});
|
|
7444
|
-
var MARKETPLACE_DISPLAY_FIELDS = [
|
|
7445
|
-
"status",
|
|
7446
|
-
"downloads",
|
|
7447
|
-
"likes",
|
|
7448
|
-
"author",
|
|
7449
|
-
"category",
|
|
7450
|
-
"visibility",
|
|
7451
|
-
"icon",
|
|
7452
|
-
"homepage",
|
|
7453
|
-
"size"
|
|
7454
|
-
];
|
|
7455
|
-
var DisplaySchema = z.object({
|
|
7456
|
-
fields: z.array(z.string().min(1)).optional()
|
|
7457
|
-
});
|
|
7458
|
-
var CategoryNodeSchema = z.lazy(
|
|
7459
|
-
() => z.object({
|
|
7460
|
-
id: z.string().min(1),
|
|
7461
|
-
label: z.string().min(1).optional(),
|
|
7462
|
-
children: z.array(CategoryNodeSchema).optional()
|
|
7463
|
-
})
|
|
7464
|
-
);
|
|
7465
|
-
var CategoriesSchema = z.array(CategoryNodeSchema).refine(hasUniqueCategoryIds, { message: "category ids must be unique across the whole tree" }).optional().catch(void 0);
|
|
7466
|
-
function hasUniqueCategoryIds(nodes) {
|
|
7467
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7468
|
-
const walk3 = (list) => list.every((node) => {
|
|
7469
|
-
if (seen.has(node.id)) return false;
|
|
7470
|
-
seen.add(node.id);
|
|
7471
|
-
return node.children === void 0 || walk3(node.children);
|
|
7472
|
-
});
|
|
7473
|
-
return walk3(nodes);
|
|
7474
|
-
}
|
|
7475
|
-
var CatalogSchema = z.object({
|
|
7476
|
-
name: z.string().regex(NAME_PATTERN),
|
|
7477
|
-
description: z.string().min(1).optional(),
|
|
7478
|
-
owner: z.object({ name: z.string().min(1), url: z.string().min(1).optional() }).optional(),
|
|
7479
|
-
display: DisplaySchema.optional(),
|
|
7480
|
-
categories: CategoriesSchema,
|
|
7481
|
-
plugins: z.array(EntrySchema)
|
|
7482
|
-
});
|
|
7483
|
-
var RecordSchema2 = z.object({
|
|
7484
|
-
name: z.string().regex(NAME_PATTERN),
|
|
7485
|
-
source: z.string().min(1),
|
|
7486
|
-
addedAt: z.number(),
|
|
7487
|
-
catalog: CatalogSchema
|
|
7488
|
-
});
|
|
7489
|
-
var StateSchema2 = z.object({
|
|
7490
|
-
version: z.literal(1).optional(),
|
|
7491
|
-
marketplaces: z.array(RecordSchema2)
|
|
7492
|
-
});
|
|
7493
|
-
function projectEntryForDisplay(entry, display) {
|
|
7494
|
-
const allowed = display?.fields;
|
|
7495
|
-
if (allowed === void 0) return entry;
|
|
7496
|
-
const out = { ...entry };
|
|
7497
|
-
for (const field of MARKETPLACE_DISPLAY_FIELDS) {
|
|
7498
|
-
if (!displayAllows(display, field)) delete out[field];
|
|
7498
|
+
async function runInstall(resolved, staging, opts) {
|
|
7499
|
+
const rootStaging = join(staging, "root");
|
|
7500
|
+
const fetched = await fetchInto(resolved, rootStaging, opts);
|
|
7501
|
+
if (!fetched.ok) return { ok: false, reason: fetched.reason };
|
|
7502
|
+
const readDir = resolved.type === "local" ? resolved.target : pluginRoot(resolved, rootStaging);
|
|
7503
|
+
const read = readPluginManifest(readDir);
|
|
7504
|
+
const manifest = read.manifest;
|
|
7505
|
+
if (!manifest) {
|
|
7506
|
+
const detail = read.issues.map((i) => t("plugin_install.issue_line", { path: i.path, message: i.message })).join("\n");
|
|
7507
|
+
return { ok: false, reason: t("plugin_install.manifest_unusable", { detail: `
|
|
7508
|
+
${detail}` }) };
|
|
7499
7509
|
}
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
const
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7510
|
+
const taken = new PluginStore(opts.statePath).read().records.find((r) => r.name === manifest.name);
|
|
7511
|
+
const conflict = taken && taken.name !== opts.replace ? taken : void 0;
|
|
7512
|
+
const current = opts.epochVersion ?? currentEpochVersion();
|
|
7513
|
+
const version = checkEpochVersion(manifest.epochVersion, current);
|
|
7514
|
+
const versionUnmet = !version.ok && manifest.epochVersion ? { required: manifest.epochVersion, current, reason: version.reason } : void 0;
|
|
7515
|
+
const closure = await resolveClosure({
|
|
7516
|
+
root: manifest.name,
|
|
7517
|
+
declared: manifest.dependencies ?? [],
|
|
7518
|
+
installed: new Map(
|
|
7519
|
+
new PluginStore(opts.statePath).read().records.map((r) => [r.name, r.path])
|
|
7520
|
+
),
|
|
7521
|
+
staging,
|
|
7522
|
+
opts
|
|
7523
|
+
});
|
|
7524
|
+
const preview3 = {
|
|
7525
|
+
manifest,
|
|
7526
|
+
source: resolved,
|
|
7527
|
+
inventory: scanPluginDir(readDir, manifest.name),
|
|
7528
|
+
...conflict ? { conflict } : {},
|
|
7529
|
+
...versionUnmet ? { versionUnmet } : {},
|
|
7530
|
+
...closure.report.length > 0 ? { dependencies: closure.report } : {}
|
|
7531
|
+
};
|
|
7532
|
+
if (opts.replace !== void 0 && manifest.name !== opts.replace) {
|
|
7513
7533
|
return {
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
]
|
|
7534
|
+
ok: false,
|
|
7535
|
+
preview: preview3,
|
|
7536
|
+
reason: t("plugin_install.renamed", { found: manifest.name, expected: opts.replace })
|
|
7518
7537
|
};
|
|
7519
7538
|
}
|
|
7520
|
-
|
|
7521
|
-
if (!checked.value) {
|
|
7539
|
+
if (conflict) {
|
|
7522
7540
|
return {
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7541
|
+
ok: false,
|
|
7542
|
+
preview: preview3,
|
|
7543
|
+
reason: t("plugin_install.already_installed", {
|
|
7544
|
+
name: conflict.name,
|
|
7545
|
+
version: conflict.version,
|
|
7546
|
+
source: conflict.source
|
|
7547
|
+
})
|
|
7528
7548
|
};
|
|
7529
7549
|
}
|
|
7530
|
-
|
|
7531
|
-
}
|
|
7532
|
-
async function mutate(statePath, fn) {
|
|
7533
|
-
const release = await acquireStateLock(statePath);
|
|
7534
|
-
try {
|
|
7535
|
-
const next = fn(readMarketplaces(statePath).records);
|
|
7536
|
-
if (!next) return false;
|
|
7537
|
-
writeStateFile(statePath, JSON.stringify({ version: 1, marketplaces: next }, null, 2));
|
|
7538
|
-
return true;
|
|
7539
|
-
} finally {
|
|
7540
|
-
release();
|
|
7550
|
+
if (opts.confirm && !await opts.confirm(preview3)) {
|
|
7551
|
+
return { ok: false, reason: t("plugin.install_cancelled"), cancelled: true, preview: preview3 };
|
|
7541
7552
|
}
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7553
|
+
const records = await commitAll(
|
|
7554
|
+
[
|
|
7555
|
+
{
|
|
7556
|
+
name: manifest.name,
|
|
7557
|
+
version: manifest.version,
|
|
7558
|
+
source: resolved,
|
|
7559
|
+
stagingDir: rootStaging,
|
|
7560
|
+
...opts.marketplace ? { marketplace: opts.marketplace } : {}
|
|
7561
|
+
},
|
|
7562
|
+
...closure.plans.map((plan) => ({
|
|
7563
|
+
name: plan.name,
|
|
7564
|
+
version: plan.manifest.version,
|
|
7565
|
+
source: plan.source,
|
|
7566
|
+
stagingDir: plan.stagingDir,
|
|
7567
|
+
...plan.marketplace ? { marketplace: plan.marketplace } : {}
|
|
7568
|
+
}))
|
|
7569
|
+
],
|
|
7570
|
+
opts
|
|
7555
7571
|
);
|
|
7556
|
-
|
|
7572
|
+
const record = records?.find((r) => r.name === manifest.name);
|
|
7573
|
+
return record ? { ok: true, record, preview: preview3 } : {
|
|
7557
7574
|
ok: false,
|
|
7558
|
-
|
|
7575
|
+
preview: preview3,
|
|
7576
|
+
reason: t("plugin_install.raced", { name: manifest.name })
|
|
7559
7577
|
};
|
|
7560
7578
|
}
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7579
|
+
var DEPENDENCY_LIMIT = 32;
|
|
7580
|
+
async function commitAll(entries2, opts) {
|
|
7581
|
+
const records = [];
|
|
7582
|
+
for (const entry of entries2) {
|
|
7583
|
+
const dest = join(opts.pluginsDir, entry.name);
|
|
7584
|
+
removeInstallDest(dest);
|
|
7585
|
+
let linked = entry.source.type === "local";
|
|
7586
|
+
if (linked) {
|
|
7587
|
+
try {
|
|
7588
|
+
symlinkSync(entry.source.target, dest, "junction");
|
|
7589
|
+
} catch {
|
|
7590
|
+
opts.onProgress?.(t("plugin_install.symlink_failed"));
|
|
7591
|
+
cpSync(entry.source.target, dest, { recursive: true });
|
|
7592
|
+
linked = false;
|
|
7593
|
+
}
|
|
7594
|
+
} else {
|
|
7595
|
+
renameSync(pluginRoot(entry.source, entry.stagingDir), dest);
|
|
7596
|
+
}
|
|
7597
|
+
records.push({
|
|
7598
|
+
name: entry.name,
|
|
7599
|
+
version: entry.version,
|
|
7600
|
+
source: entry.source.raw,
|
|
7601
|
+
sourceType: entry.source.type,
|
|
7602
|
+
path: dest,
|
|
7603
|
+
linked,
|
|
7604
|
+
enabled: true,
|
|
7605
|
+
installedAt: Date.now(),
|
|
7606
|
+
...entry.marketplace ? { marketplace: entry.marketplace } : {},
|
|
7607
|
+
...entry.source.sha256 ? { checksum: `sha256:${entry.source.sha256}` } : {}
|
|
7608
|
+
});
|
|
7581
7609
|
}
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7610
|
+
return new PluginStore(opts.statePath).mutate((existing) => {
|
|
7611
|
+
for (const record of records) {
|
|
7612
|
+
const taken = existing.some((r) => r.name === record.name);
|
|
7613
|
+
if (taken && opts.replace !== record.name) return void 0;
|
|
7614
|
+
}
|
|
7615
|
+
let next = existing;
|
|
7616
|
+
for (const record of records) {
|
|
7617
|
+
const taken = next.some((r) => r.name === record.name);
|
|
7618
|
+
next = taken ? next.map((r) => r.name === record.name ? record : r) : [...next, record];
|
|
7619
|
+
}
|
|
7620
|
+
return { records: next, result: records };
|
|
7621
|
+
});
|
|
7585
7622
|
}
|
|
7586
|
-
function
|
|
7587
|
-
const
|
|
7588
|
-
const
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7623
|
+
async function resolveClosure(input) {
|
|
7624
|
+
const { opts, staging } = input;
|
|
7625
|
+
const seen = /* @__PURE__ */ new Set([input.root]);
|
|
7626
|
+
const queue = input.declared.map((name) => ({
|
|
7627
|
+
name,
|
|
7628
|
+
requiredBy: input.root
|
|
7629
|
+
}));
|
|
7630
|
+
const report3 = [];
|
|
7631
|
+
const plans = [];
|
|
7632
|
+
while (queue.length > 0) {
|
|
7633
|
+
const next = queue.shift();
|
|
7634
|
+
if (!next) break;
|
|
7635
|
+
const { name, requiredBy } = next;
|
|
7636
|
+
if (seen.has(name)) continue;
|
|
7637
|
+
seen.add(name);
|
|
7638
|
+
const installedAt = input.installed.get(name);
|
|
7639
|
+
if (installedAt !== void 0) {
|
|
7640
|
+
report3.push({
|
|
7641
|
+
name,
|
|
7642
|
+
status: "installed",
|
|
7643
|
+
requiredBy,
|
|
7644
|
+
...installedDisplayName(installedAt)
|
|
7603
7645
|
});
|
|
7646
|
+
continue;
|
|
7647
|
+
}
|
|
7648
|
+
if (plans.length >= DEPENDENCY_LIMIT) {
|
|
7649
|
+
report3.push({
|
|
7650
|
+
name,
|
|
7651
|
+
status: "unresolved",
|
|
7652
|
+
requiredBy,
|
|
7653
|
+
reason: t("plugin_install.dep_too_many", { limit: DEPENDENCY_LIMIT, root: input.root })
|
|
7654
|
+
});
|
|
7655
|
+
continue;
|
|
7656
|
+
}
|
|
7657
|
+
const located = await locateDependency(name, opts);
|
|
7658
|
+
if (!located) {
|
|
7659
|
+
report3.push({
|
|
7660
|
+
name,
|
|
7661
|
+
status: "unresolved",
|
|
7662
|
+
requiredBy,
|
|
7663
|
+
reason: t("plugin_install.dep_no_source", { name })
|
|
7664
|
+
});
|
|
7665
|
+
continue;
|
|
7666
|
+
}
|
|
7667
|
+
const source = resolveSource(located.source);
|
|
7668
|
+
if (!source) {
|
|
7669
|
+
report3.push({
|
|
7670
|
+
name,
|
|
7671
|
+
status: "unresolved",
|
|
7672
|
+
requiredBy,
|
|
7673
|
+
source: located.source,
|
|
7674
|
+
reason: t("plugin_install.dep_bad_source", { name, source: located.source })
|
|
7675
|
+
});
|
|
7676
|
+
continue;
|
|
7677
|
+
}
|
|
7678
|
+
opts.onProgress?.(t("plugin_install.dep_fetching", { name, source: located.source }));
|
|
7679
|
+
const stagingDir = join(staging, `dep-${plans.length}`);
|
|
7680
|
+
const fetched = await fetchInto(source, stagingDir, opts);
|
|
7681
|
+
if (!fetched.ok) {
|
|
7682
|
+
report3.push({
|
|
7683
|
+
name,
|
|
7684
|
+
status: "unresolved",
|
|
7685
|
+
requiredBy,
|
|
7686
|
+
source: located.source,
|
|
7687
|
+
reason: fetched.reason
|
|
7688
|
+
});
|
|
7689
|
+
continue;
|
|
7690
|
+
}
|
|
7691
|
+
const readDir = source.type === "local" ? source.target : pluginRoot(source, stagingDir);
|
|
7692
|
+
const read = readPluginManifest(readDir);
|
|
7693
|
+
const manifest = read.manifest;
|
|
7694
|
+
if (!manifest) {
|
|
7695
|
+
report3.push({
|
|
7696
|
+
name,
|
|
7697
|
+
status: "unresolved",
|
|
7698
|
+
requiredBy,
|
|
7699
|
+
source: located.source,
|
|
7700
|
+
reason: t("plugin_install.dep_bad_manifest", {
|
|
7701
|
+
name,
|
|
7702
|
+
detail: read.issues.map((issue) => issue.message).join("; ")
|
|
7703
|
+
})
|
|
7704
|
+
});
|
|
7705
|
+
continue;
|
|
7706
|
+
}
|
|
7707
|
+
if (manifest.name !== name) {
|
|
7708
|
+
report3.push({
|
|
7709
|
+
name,
|
|
7710
|
+
status: "unresolved",
|
|
7711
|
+
requiredBy,
|
|
7712
|
+
source: located.source,
|
|
7713
|
+
reason: t("plugin_install.dep_name_mismatch", { name, found: manifest.name })
|
|
7714
|
+
});
|
|
7715
|
+
continue;
|
|
7716
|
+
}
|
|
7717
|
+
const current = opts.epochVersion ?? currentEpochVersion();
|
|
7718
|
+
const version = checkEpochVersion(manifest.epochVersion, current);
|
|
7719
|
+
const versionUnmet = !version.ok && manifest.epochVersion ? { required: manifest.epochVersion, current, reason: version.reason } : void 0;
|
|
7720
|
+
report3.push({
|
|
7721
|
+
name,
|
|
7722
|
+
status: "plan",
|
|
7723
|
+
requiredBy,
|
|
7724
|
+
source: located.source,
|
|
7725
|
+
...manifest.displayName ? { displayName: manifest.displayName } : {},
|
|
7726
|
+
manifest,
|
|
7727
|
+
inventory: scanPluginDir(readDir, manifest.name),
|
|
7728
|
+
...versionUnmet ? { versionUnmet } : {}
|
|
7729
|
+
});
|
|
7730
|
+
plans.push({
|
|
7731
|
+
name: manifest.name,
|
|
7732
|
+
source,
|
|
7733
|
+
stagingDir,
|
|
7734
|
+
manifest,
|
|
7735
|
+
...located.marketplace ? { marketplace: located.marketplace } : {}
|
|
7736
|
+
});
|
|
7737
|
+
for (const nested of manifest.dependencies ?? []) {
|
|
7738
|
+
queue.push({ name: nested, requiredBy: manifest.name });
|
|
7604
7739
|
}
|
|
7605
7740
|
}
|
|
7606
|
-
return
|
|
7741
|
+
return { report: report3, plans };
|
|
7607
7742
|
}
|
|
7608
|
-
function
|
|
7609
|
-
const
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
const
|
|
7614
|
-
if (
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
};
|
|
7743
|
+
function installedDisplayName(dir) {
|
|
7744
|
+
const displayName = readPluginManifest(dir).manifest?.displayName;
|
|
7745
|
+
return displayName ? { displayName } : {};
|
|
7746
|
+
}
|
|
7747
|
+
async function locateDependency(name, opts) {
|
|
7748
|
+
const local = opts.marketplacesStatePath ? findMarketplaceEntryByName(name, opts.marketplacesStatePath) : void 0;
|
|
7749
|
+
if (local) return { source: local.source, marketplace: local.marketplace };
|
|
7750
|
+
if (!opts.resolveDependency) return void 0;
|
|
7751
|
+
try {
|
|
7752
|
+
const answer = await opts.resolveDependency(name);
|
|
7753
|
+
return answer ? { source: answer } : void 0;
|
|
7754
|
+
} catch {
|
|
7755
|
+
return void 0;
|
|
7619
7756
|
}
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7757
|
+
}
|
|
7758
|
+
function removeInstallDest(dest) {
|
|
7759
|
+
let link = false;
|
|
7760
|
+
try {
|
|
7761
|
+
link = lstatSync(dest).isSymbolicLink();
|
|
7762
|
+
} catch {
|
|
7626
7763
|
}
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
return
|
|
7630
|
-
ok: false,
|
|
7631
|
-
reason: t("plugin_marketplace.entry_unresolvable", {
|
|
7632
|
-
market,
|
|
7633
|
-
plugin,
|
|
7634
|
-
source: entry.source
|
|
7635
|
-
})
|
|
7636
|
-
};
|
|
7764
|
+
if (!link) {
|
|
7765
|
+
rmSync(dest, { recursive: true, force: true });
|
|
7766
|
+
return;
|
|
7637
7767
|
}
|
|
7638
|
-
|
|
7768
|
+
try {
|
|
7769
|
+
unlinkSync(dest);
|
|
7770
|
+
} catch {
|
|
7771
|
+
rmdirSync(dest);
|
|
7772
|
+
}
|
|
7773
|
+
}
|
|
7774
|
+
async function fetchInto(source, staging, opts) {
|
|
7775
|
+
if (source.type === "local") return fetchLocal(source);
|
|
7776
|
+
if (source.type === "git") return fetchGit(source, staging, opts);
|
|
7777
|
+
if (source.type === "npm") return fetchNpm(source, staging, opts);
|
|
7778
|
+
if (source.type === "host") return fetchFromHost(source, staging, opts);
|
|
7779
|
+
if (source.localFile) return fetchLocalArchive(source, staging);
|
|
7780
|
+
return fetchArchive(source, staging, opts);
|
|
7781
|
+
}
|
|
7782
|
+
async function fetchLocalArchive(source, staging) {
|
|
7783
|
+
if (!existsSync(source.target)) {
|
|
7784
|
+
return { ok: false, reason: t("plugin_install.archive_missing", { path: source.target }) };
|
|
7785
|
+
}
|
|
7786
|
+
mkdirSync(staging, { recursive: true });
|
|
7787
|
+
return extractArchive(source.target, staging);
|
|
7788
|
+
}
|
|
7789
|
+
async function fetchFromHost(source, staging, opts) {
|
|
7790
|
+
const ask = opts.fetchFromHost;
|
|
7791
|
+
if (!ask) {
|
|
7792
|
+
return { ok: false, reason: t("plugin_install.host_fetch_unavailable") };
|
|
7793
|
+
}
|
|
7794
|
+
opts.onProgress?.(t("plugin_install.host_fetching", { target: source.target }));
|
|
7795
|
+
mkdirSync(staging, { recursive: true });
|
|
7796
|
+
return withDownloadDir(async (dl) => {
|
|
7797
|
+
let answer;
|
|
7798
|
+
try {
|
|
7799
|
+
answer = await ask({ target: source.target, destDir: dl });
|
|
7800
|
+
} catch (err) {
|
|
7801
|
+
return {
|
|
7802
|
+
ok: false,
|
|
7803
|
+
reason: t("plugin_install.host_fetch_threw", {
|
|
7804
|
+
reason: (err instanceof Error ? err.message : String(err)).split("\n")[0] ?? ""
|
|
7805
|
+
})
|
|
7806
|
+
};
|
|
7807
|
+
}
|
|
7808
|
+
if (!answer.ok) {
|
|
7809
|
+
return {
|
|
7810
|
+
ok: false,
|
|
7811
|
+
reason: answer.reason ?? t("plugin_install.host_fetch_failed", { target: source.target })
|
|
7812
|
+
};
|
|
7813
|
+
}
|
|
7814
|
+
if (!existsSync(answer.archivePath)) {
|
|
7815
|
+
return {
|
|
7816
|
+
ok: false,
|
|
7817
|
+
reason: t("plugin_install.host_fetch_no_file", { path: answer.archivePath })
|
|
7818
|
+
};
|
|
7819
|
+
}
|
|
7820
|
+
return extractArchive(answer.archivePath, staging);
|
|
7821
|
+
});
|
|
7639
7822
|
}
|
|
7640
|
-
function
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
const rel = spec.replace(/^\.\//, "").replace(/^\//, "");
|
|
7644
|
-
if (rel === "" || rel.split("/").includes("..")) return void 0;
|
|
7645
|
-
const market = marketSource.trim();
|
|
7646
|
-
if (market.startsWith("github:") || market.startsWith("git+")) {
|
|
7647
|
-
const [base = "", fragment] = market.split("#", 2);
|
|
7648
|
-
const prefix = fragment?.startsWith("subdir=") ? `${fragment.slice("subdir=".length)}/` : "";
|
|
7649
|
-
return `${base}#subdir=${prefix}${rel}`;
|
|
7823
|
+
function fetchLocal(source) {
|
|
7824
|
+
if (!existsSync(source.target)) {
|
|
7825
|
+
return { ok: false, reason: t("plugin_install.local_missing", { path: source.target }) };
|
|
7650
7826
|
}
|
|
7651
|
-
|
|
7652
|
-
|
|
7827
|
+
return { ok: true };
|
|
7828
|
+
}
|
|
7829
|
+
async function fetchGit(source, staging, opts) {
|
|
7830
|
+
opts.onProgress?.(t("plugin_install.cloning", { target: source.target }));
|
|
7831
|
+
const result = await runCommand("git", ["clone", "--depth", "1", source.target, staging]);
|
|
7832
|
+
if (!result.ok) {
|
|
7833
|
+
return { ok: false, reason: t("plugin_install.clone_failed", { detail: result.detail }) };
|
|
7653
7834
|
}
|
|
7654
|
-
|
|
7835
|
+
rmSync(join(staging, ".git"), { recursive: true, force: true });
|
|
7836
|
+
return { ok: true };
|
|
7655
7837
|
}
|
|
7656
|
-
async function
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
7838
|
+
async function fetchNpm(source, staging, opts) {
|
|
7839
|
+
opts.onProgress?.(t("plugin_install.npm_fetching", { target: source.target }));
|
|
7840
|
+
mkdirSync(staging, { recursive: true });
|
|
7841
|
+
return withDownloadDir(async (dl) => {
|
|
7842
|
+
const packed = await runCommand(
|
|
7843
|
+
"npm",
|
|
7844
|
+
["pack", source.target, "--pack-destination", dl, "--silent"],
|
|
7845
|
+
{ cwd: dl, windowsShell: true }
|
|
7846
|
+
);
|
|
7847
|
+
if (!packed.ok) {
|
|
7848
|
+
return { ok: false, reason: t("plugin_install.npm_pack_failed", { detail: packed.detail }) };
|
|
7663
7849
|
}
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7850
|
+
const tarball = packed.stdout.trim().split("\n").pop()?.trim();
|
|
7851
|
+
if (!tarball) return { ok: false, reason: t("plugin_install.npm_no_tarball") };
|
|
7852
|
+
return extractArchive(isAbsolute(tarball) ? tarball : join(dl, tarball), staging);
|
|
7853
|
+
});
|
|
7854
|
+
}
|
|
7855
|
+
async function fetchArchive(source, staging, opts) {
|
|
7856
|
+
opts.onProgress?.(t("plugin_install.downloading", { target: source.target }));
|
|
7857
|
+
mkdirSync(staging, { recursive: true });
|
|
7858
|
+
let bytes;
|
|
7859
|
+
try {
|
|
7860
|
+
const response = await fetch(source.target, { redirect: "follow" });
|
|
7861
|
+
if (!response.ok) {
|
|
7862
|
+
return {
|
|
7863
|
+
ok: false,
|
|
7864
|
+
reason: t("plugin_install.download_http", {
|
|
7865
|
+
status: response.status,
|
|
7866
|
+
statusText: response.statusText
|
|
7867
|
+
})
|
|
7868
|
+
};
|
|
7668
7869
|
}
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
if (!url) {
|
|
7870
|
+
bytes = Buffer.from(await response.arrayBuffer());
|
|
7871
|
+
} catch (err) {
|
|
7672
7872
|
return {
|
|
7673
7873
|
ok: false,
|
|
7674
|
-
reason: t("
|
|
7874
|
+
reason: t("plugin_install.download_failed", {
|
|
7875
|
+
message: err instanceof Error ? err.message : String(err)
|
|
7876
|
+
})
|
|
7675
7877
|
};
|
|
7676
7878
|
}
|
|
7677
|
-
|
|
7678
|
-
const
|
|
7679
|
-
if (
|
|
7680
|
-
const vars = { url, status: response.status };
|
|
7879
|
+
if (source.sha256) {
|
|
7880
|
+
const actual = createHash("sha256").update(bytes).digest("hex");
|
|
7881
|
+
if (actual !== source.sha256) {
|
|
7681
7882
|
return {
|
|
7682
7883
|
ok: false,
|
|
7683
|
-
reason:
|
|
7884
|
+
reason: [
|
|
7885
|
+
t("plugin_install.sha_mismatch"),
|
|
7886
|
+
t("plugin_install.sha_expected", { expected: source.sha256 }),
|
|
7887
|
+
t("plugin_install.sha_actual", { actual })
|
|
7888
|
+
].join("\n")
|
|
7684
7889
|
};
|
|
7685
7890
|
}
|
|
7686
|
-
return parseCatalog(await response.text(), url);
|
|
7687
|
-
} catch (err) {
|
|
7688
|
-
return { ok: false, reason: t("marketplace.fetch_error", { url, reason: first(err) }) };
|
|
7689
7891
|
}
|
|
7892
|
+
return withDownloadDir(async (dl) => {
|
|
7893
|
+
const archive = join(dl, `download${archiveExt(source.target)}`);
|
|
7894
|
+
writeFileSync(archive, bytes);
|
|
7895
|
+
return extractArchive(archive, staging);
|
|
7896
|
+
});
|
|
7690
7897
|
}
|
|
7691
|
-
function
|
|
7692
|
-
|
|
7898
|
+
function archiveExt(url) {
|
|
7899
|
+
const path = (url.split("?")[0] ?? "").toLowerCase();
|
|
7900
|
+
if (path.endsWith(".tgz")) return ".tgz";
|
|
7901
|
+
if (path.endsWith(".tar.gz")) return ".tar.gz";
|
|
7902
|
+
return ".zip";
|
|
7693
7903
|
}
|
|
7694
|
-
function
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
7904
|
+
async function withDownloadDir(fn) {
|
|
7905
|
+
const dir = mkdtempSync(join(tmpdir(), "epoch-plugin-dl-"));
|
|
7906
|
+
try {
|
|
7907
|
+
return await fn(dir);
|
|
7908
|
+
} finally {
|
|
7909
|
+
rmSync(dir, { recursive: true, force: true });
|
|
7699
7910
|
}
|
|
7700
|
-
if (!input.startsWith("https://") && !input.startsWith("http://")) return void 0;
|
|
7701
|
-
return input.endsWith(".json") ? input : `${input.replace(/\/+$/, "")}/${MARKETPLACE_FILE}`;
|
|
7702
7911
|
}
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
return
|
|
7912
|
+
// src/plugin/root-token.ts
|
|
7913
|
+
var PLUGIN_ROOT_TOKEN = "${EPOCH_PLUGIN_ROOT}";
|
|
7914
|
+
var PLUGIN_ROOT_ENV = "EPOCH_PLUGIN_ROOT";
|
|
7915
|
+
function mentionsPluginRoot(text) {
|
|
7916
|
+
return text.includes(PLUGIN_ROOT_TOKEN);
|
|
7708
7917
|
}
|
|
7709
|
-
function
|
|
7710
|
-
|
|
7711
|
-
if (existsSync(abs) && statSync(abs).isDirectory()) return abs;
|
|
7712
|
-
return abs.replace(/[/\\][^/\\]*$/, "");
|
|
7918
|
+
function substitutePluginRoot(text, root) {
|
|
7919
|
+
return text.split(PLUGIN_ROOT_TOKEN).join(root);
|
|
7713
7920
|
}
|
|
7714
|
-
function
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
|
|
7718
|
-
|
|
7921
|
+
async function uninstallPlugin(name, opts) {
|
|
7922
|
+
const removed = await new PluginStore(opts.statePath).mutate((records) => {
|
|
7923
|
+
const hit = records.find((r) => r.name === name);
|
|
7924
|
+
if (!hit) return void 0;
|
|
7925
|
+
return { records: records.filter((r) => r.name !== name), result: hit };
|
|
7926
|
+
});
|
|
7927
|
+
if (!removed) return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7928
|
+
if (removed.linked) {
|
|
7929
|
+
rmSync(removed.path, { force: true });
|
|
7930
|
+
return { ok: true, message: t("plugin_lifecycle.uninstalled_link", { name }) };
|
|
7931
|
+
}
|
|
7932
|
+
rmSync(removed.path, { recursive: true, force: true });
|
|
7933
|
+
return { ok: true, message: t("plugin_lifecycle.uninstalled", { name }) };
|
|
7934
|
+
}
|
|
7935
|
+
async function setPluginEnabled(name, enabled, opts) {
|
|
7936
|
+
const changed = await new PluginStore(opts.statePath).mutate((records) => {
|
|
7937
|
+
const hit = records.find((r) => r.name === name);
|
|
7938
|
+
if (!hit) return void 0;
|
|
7719
7939
|
return {
|
|
7720
|
-
|
|
7721
|
-
|
|
7940
|
+
records: records.map((r) => r.name === name ? { ...r, enabled } : r),
|
|
7941
|
+
result: hit.enabled !== enabled
|
|
7722
7942
|
};
|
|
7943
|
+
});
|
|
7944
|
+
if (changed === void 0) {
|
|
7945
|
+
return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7723
7946
|
}
|
|
7724
|
-
const
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
}
|
|
7729
|
-
return { ok: true, catalog: checked.value };
|
|
7947
|
+
const verb = enabled ? t("plugin_lifecycle.verb_enable") : t("plugin_lifecycle.verb_disable");
|
|
7948
|
+
return {
|
|
7949
|
+
ok: true,
|
|
7950
|
+
message: changed ? t("plugin_lifecycle.toggled", { verb, name }) : t("plugin_lifecycle.already", { name, verb })
|
|
7951
|
+
};
|
|
7730
7952
|
}
|
|
7731
|
-
function
|
|
7732
|
-
const
|
|
7733
|
-
|
|
7953
|
+
async function updatePlugin(name, opts) {
|
|
7954
|
+
const existing = new PluginStore(opts.statePath).read().records.find((r) => r.name === name);
|
|
7955
|
+
if (!existing) return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7956
|
+
if (existing.linked) {
|
|
7957
|
+
return {
|
|
7958
|
+
ok: true,
|
|
7959
|
+
message: t("plugin_lifecycle.linked_no_update", { name, source: existing.source })
|
|
7960
|
+
};
|
|
7961
|
+
}
|
|
7962
|
+
return installPlugin(existing.source, {
|
|
7963
|
+
...opts,
|
|
7964
|
+
replace: name,
|
|
7965
|
+
...existing.marketplace ? { marketplace: existing.marketplace } : {}
|
|
7966
|
+
});
|
|
7734
7967
|
}
|
|
7735
7968
|
var TMP_SUFFIX = ".epoch-rewind";
|
|
7736
7969
|
function planFor(entry, current) {
|
|
@@ -7778,7 +8011,7 @@ async function applyRewind(store, sessionId, manifest, apply, skippedConflicts)
|
|
|
7778
8011
|
} catch (err) {
|
|
7779
8012
|
return { ...empty, failed: t("rewind.stage_failed", { message: messageOf(err) }) };
|
|
7780
8013
|
}
|
|
7781
|
-
return
|
|
8014
|
+
return commitAll2(staged, skippedConflicts);
|
|
7782
8015
|
}
|
|
7783
8016
|
async function stageAll(store, sessionId, manifest, todo, byPath) {
|
|
7784
8017
|
const staged = [];
|
|
@@ -7806,7 +8039,7 @@ async function stageAll(store, sessionId, manifest, todo, byPath) {
|
|
|
7806
8039
|
}
|
|
7807
8040
|
return staged;
|
|
7808
8041
|
}
|
|
7809
|
-
async function
|
|
8042
|
+
async function commitAll2(staged, skippedConflicts) {
|
|
7810
8043
|
const outcome = {
|
|
7811
8044
|
restored: [],
|
|
7812
8045
|
deleted: [],
|
|
@@ -8265,7 +8498,8 @@ function asStringList(value) {
|
|
|
8265
8498
|
return value.filter((v) => typeof v === "string" && v.length > 0);
|
|
8266
8499
|
}
|
|
8267
8500
|
function toAbsolute(path, workDir) {
|
|
8268
|
-
|
|
8501
|
+
const expanded = expandPath(path);
|
|
8502
|
+
return isAbsolute(expanded) ? resolve(expanded) : resolve(workDir, expanded);
|
|
8269
8503
|
}
|
|
8270
8504
|
var MAX_FILE_BYTES2 = 128 * 1024;
|
|
8271
8505
|
var MAX_CALL_BYTES = 512 * 1024;
|
|
@@ -8676,8 +8910,8 @@ function sanitizeToolOutput(text) {
|
|
|
8676
8910
|
if (!stripped.includes("\r")) return stripped;
|
|
8677
8911
|
return stripped.split("\n").map((line) => line.includes("\r") ? line.slice(line.lastIndexOf("\r") + 1) : line).join("\n");
|
|
8678
8912
|
}
|
|
8679
|
-
var sleep2 = (ms) => new Promise((
|
|
8680
|
-
setTimeout(
|
|
8913
|
+
var sleep2 = (ms) => new Promise((resolve17) => {
|
|
8914
|
+
setTimeout(resolve17, ms);
|
|
8681
8915
|
});
|
|
8682
8916
|
async function* pumpToolOutput(target, start, options = {}) {
|
|
8683
8917
|
const flushMs = options.flushMs ?? FLUSH_MS;
|
|
@@ -8745,8 +8979,8 @@ async function* pumpToolOutput(target, start, options = {}) {
|
|
|
8745
8979
|
continue;
|
|
8746
8980
|
}
|
|
8747
8981
|
if (!running) break;
|
|
8748
|
-
await new Promise((
|
|
8749
|
-
wake =
|
|
8982
|
+
await new Promise((resolve17) => {
|
|
8983
|
+
wake = resolve17;
|
|
8750
8984
|
});
|
|
8751
8985
|
if (running && flushMs > 0) await sleep2(flushMs);
|
|
8752
8986
|
}
|
|
@@ -8762,10 +8996,11 @@ var REPLY_LANG_RULE = {
|
|
|
8762
8996
|
var REPLY_LANG_MATCH_USER = "- \u7528\u7528\u6237\u8DDF\u4F60\u8BF4\u8BDD\u7684\u90A3\u79CD\u8BED\u8A00\u56DE\u590D\u4ED6\uFF1A\u6B63\u6587\u548C\u601D\u8003\u90FD\u7528\u90A3\u79CD\u8BED\u8A00\u3002\u4EE3\u7801\u5E93\u3001\u5DE5\u5177\u8F93\u51FA\u3001\u62A5\u9519\u662F\u4EC0\u4E48\u8BED\u8A00\uFF0C\u90FD\u4E0D\u6539\u53D8\u8FD9\u4E00\u6761";
|
|
8763
8997
|
function identityLine(role) {
|
|
8764
8998
|
if (!role) return "\u4F60\u662F\u4E00\u4E2A\u672C\u5730\u667A\u80FD\u4F53\uFF0C\u53EF\u4EE5\u6267\u884C\u7EC8\u7AEF\u547D\u4EE4\u548C\u64CD\u4F5C\u6587\u4EF6\u3002";
|
|
8999
|
+
const who = role.displayName ?? role.name;
|
|
8765
9000
|
if (role.scope === "session") {
|
|
8766
|
-
return `\u4F60\u662F\u4E00\u4E2A\u672C\u5730\u667A\u80FD\u4F53\uFF0C\u8FD9\u4E00\u6B21\u4EE5\u300C${
|
|
9001
|
+
return `\u4F60\u662F\u4E00\u4E2A\u672C\u5730\u667A\u80FD\u4F53\uFF0C\u8FD9\u4E00\u6B21\u4EE5\u300C${who}\u300D\u7684\u8EAB\u4EFD\u5DE5\u4F5C\u3002`;
|
|
8767
9002
|
}
|
|
8768
|
-
return `\u4F60\u662F\u300C${
|
|
9003
|
+
return `\u4F60\u662F\u300C${who}\u300D\u5B50\u667A\u80FD\u4F53\uFF0C\u7531\u4E3B\u667A\u80FD\u4F53\u6D3E\u6765\u5B8C\u6210\u4E00\u4E2A\u72EC\u7ACB\u5B50\u4EFB\u52A1\u3002`;
|
|
8769
9004
|
}
|
|
8770
9005
|
function systemPromptSegments(params) {
|
|
8771
9006
|
return {
|
|
@@ -11019,6 +11254,37 @@ function pruneArtifacts(root, keepSession, retention = ARTIFACT_RETENTION_DEFAUL
|
|
|
11019
11254
|
async function removeSessionArtifacts(sessionId, homeDir) {
|
|
11020
11255
|
await rm(artifactsDir(sessionId, homeDir), { recursive: true, force: true });
|
|
11021
11256
|
}
|
|
11257
|
+
function grantedPathsFor(args, workDir, extraRoots = []) {
|
|
11258
|
+
const out = /* @__PURE__ */ new Set();
|
|
11259
|
+
const add = (raw) => {
|
|
11260
|
+
if (isInWorkspace(toAbsolute2(raw, workDir), workDir, extraRoots)) return;
|
|
11261
|
+
out.add(approvalRootFor(raw, workDir));
|
|
11262
|
+
};
|
|
11263
|
+
for (const p of affectedPaths(args, workDir)) add(p);
|
|
11264
|
+
const workdir = args["workdir"];
|
|
11265
|
+
if (typeof workdir === "string" && workdir) add(workdir);
|
|
11266
|
+
return [...out];
|
|
11267
|
+
}
|
|
11268
|
+
function approvalRootFor(target, workDir) {
|
|
11269
|
+
const abs = toAbsolute2(target, workDir);
|
|
11270
|
+
try {
|
|
11271
|
+
if (statSync(abs).isDirectory()) return abs;
|
|
11272
|
+
} catch {
|
|
11273
|
+
}
|
|
11274
|
+
return dirname(abs);
|
|
11275
|
+
}
|
|
11276
|
+
function approvalEntryFor(opTarget, workDir, grantedRoots) {
|
|
11277
|
+
const abs = toAbsolute2(opTarget, workDir);
|
|
11278
|
+
if (isInWorkspace(abs, workDir, [])) return { target: opTarget, scope: "exact" };
|
|
11279
|
+
for (const root of grantedRoots) {
|
|
11280
|
+
if (isInWorkspace(abs, workDir, [root])) return { target: root, scope: "prefix" };
|
|
11281
|
+
}
|
|
11282
|
+
return { target: opTarget, scope: "exact" };
|
|
11283
|
+
}
|
|
11284
|
+
function toAbsolute2(path, workDir) {
|
|
11285
|
+
const expanded = expandPath(path);
|
|
11286
|
+
return isAbsolute(expanded) ? resolve(expanded) : resolve(workDir, expanded);
|
|
11287
|
+
}
|
|
11022
11288
|
var MAX_TOOL_OUTPUT = 3e4;
|
|
11023
11289
|
var MAX_SUB_CALL_OUTPUT = CODE_MODE_LIMITS.maxValueChars;
|
|
11024
11290
|
function budgetOf2(tool, depth, path = "success") {
|
|
@@ -11266,6 +11532,7 @@ var ToolExecutor = class {
|
|
|
11266
11532
|
sessionId,
|
|
11267
11533
|
workDir: this.deps.workDir(),
|
|
11268
11534
|
...extraRoots?.length ? { extraRoots } : {},
|
|
11535
|
+
...gate.grantedPaths?.length ? { grantedPaths: gate.grantedPaths } : {},
|
|
11269
11536
|
...homeDir ? { homeDir } : {},
|
|
11270
11537
|
...this.deps.sandboxTerminal !== void 0 ? { sandboxTerminal: this.deps.sandboxTerminal } : {},
|
|
11271
11538
|
permissionLevel: this.deps.permissionManager?.getLevel() || "auto",
|
|
@@ -11400,6 +11667,11 @@ var ToolExecutor = class {
|
|
|
11400
11667
|
const pm = this.deps.permissionManager;
|
|
11401
11668
|
if (!pm) return { allowed: true };
|
|
11402
11669
|
const toolName = et.name;
|
|
11670
|
+
const granted = () => grantedPathsFor(args, this.deps.workDir(), pm.getExtraRoots?.() ?? []);
|
|
11671
|
+
const allow = () => {
|
|
11672
|
+
const paths = granted();
|
|
11673
|
+
return paths.length > 0 ? { allowed: true, grantedPaths: paths } : { allowed: true };
|
|
11674
|
+
};
|
|
11403
11675
|
const opType = mapOperation(et);
|
|
11404
11676
|
const opTarget = this.resolveTarget(et, args);
|
|
11405
11677
|
const opDetail = (typeof args["command"] === "string" ? args["command"] : typeof args["path"] === "string" ? args["path"] : opTarget) || argsKey(args);
|
|
@@ -11410,7 +11682,7 @@ var ToolExecutor = class {
|
|
|
11410
11682
|
target: opTarget,
|
|
11411
11683
|
toolName
|
|
11412
11684
|
});
|
|
11413
|
-
if (decision.allowed) return
|
|
11685
|
+
if (decision.allowed) return allow();
|
|
11414
11686
|
if (!decision.requireApproval) {
|
|
11415
11687
|
return { allowed: false, output: `\u64CD\u4F5C\u88AB\u62E6\u622A [\u6743\u9650]: ${decision.reason || "\u9700\u8981\u6388\u6743"}` };
|
|
11416
11688
|
}
|
|
@@ -11449,9 +11721,10 @@ var ToolExecutor = class {
|
|
|
11449
11721
|
};
|
|
11450
11722
|
}
|
|
11451
11723
|
if (outcome === "allow-session" || outcome === "allow-always") {
|
|
11452
|
-
|
|
11724
|
+
const entry = approvalEntryFor(opTarget, this.deps.workDir(), granted());
|
|
11725
|
+
pm.recordApproval(toolName, entry.target, outcome, entry.scope);
|
|
11453
11726
|
}
|
|
11454
|
-
return
|
|
11727
|
+
return allow();
|
|
11455
11728
|
}
|
|
11456
11729
|
};
|
|
11457
11730
|
// src/agent/loop.ts
|
|
@@ -11853,7 +12126,13 @@ var AgentLoop = class {
|
|
|
11853
12126
|
const role = this.config.role?.();
|
|
11854
12127
|
yield {
|
|
11855
12128
|
type: "run-start",
|
|
11856
|
-
...role ? {
|
|
12129
|
+
...role ? {
|
|
12130
|
+
role: {
|
|
12131
|
+
name: role.name,
|
|
12132
|
+
...role.displayName ? { displayName: role.displayName } : {},
|
|
12133
|
+
...role.source ? { source: role.source } : {}
|
|
12134
|
+
}
|
|
12135
|
+
} : {},
|
|
11857
12136
|
estimatedTokens: estimated
|
|
11858
12137
|
};
|
|
11859
12138
|
if (learned.length > 0) {
|
|
@@ -13371,6 +13650,10 @@ var DEFAULT_MODELS = {
|
|
|
13371
13650
|
groq: "llama-3.3-70b-versatile",
|
|
13372
13651
|
mistral: "ministral-8b-latest",
|
|
13373
13652
|
moonshotai: "kimi-latest",
|
|
13653
|
+
zhipu: "glm-4.5-flash",
|
|
13654
|
+
dashscope: "qwen-flash",
|
|
13655
|
+
bytedance: "doubao-seed-2.0-mini",
|
|
13656
|
+
qianfan: "ernie-speed-128k",
|
|
13374
13657
|
cohere: "command-r7b-12-2024",
|
|
13375
13658
|
xai: "grok-vision-beta",
|
|
13376
13659
|
perplexity: "sonar",
|
|
@@ -13783,6 +14066,10 @@ var PACKAGES = {
|
|
|
13783
14066
|
groq: "@ai-sdk/groq",
|
|
13784
14067
|
mistral: "@ai-sdk/mistral",
|
|
13785
14068
|
moonshotai: "@ai-sdk/moonshotai",
|
|
14069
|
+
zhipu: "@ai-sdk/openai-compatible",
|
|
14070
|
+
dashscope: "@ai-sdk/alibaba",
|
|
14071
|
+
bytedance: "@ai-sdk/openai-compatible",
|
|
14072
|
+
qianfan: "@ai-sdk/openai-compatible",
|
|
13786
14073
|
cohere: "@ai-sdk/cohere",
|
|
13787
14074
|
xai: "@ai-sdk/xai",
|
|
13788
14075
|
perplexity: "@ai-sdk/perplexity",
|
|
@@ -13792,6 +14079,17 @@ var PACKAGES = {
|
|
|
13792
14079
|
ollama: "ollama-ai-provider-v2",
|
|
13793
14080
|
"openai-compatible": "@ai-sdk/openai-compatible"
|
|
13794
14081
|
};
|
|
14082
|
+
function openaiCompatibleFactory(name, defaultBaseUrl) {
|
|
14083
|
+
return async ({ apiKey, baseUrl }) => {
|
|
14084
|
+
const { createOpenAICompatible } = await import('@ai-sdk/openai-compatible');
|
|
14085
|
+
return createOpenAICompatible({
|
|
14086
|
+
apiKey,
|
|
14087
|
+
baseURL: baseUrl || defaultBaseUrl,
|
|
14088
|
+
name,
|
|
14089
|
+
includeUsage: true
|
|
14090
|
+
});
|
|
14091
|
+
};
|
|
14092
|
+
}
|
|
13795
14093
|
var LOADERS = {
|
|
13796
14094
|
openai: async ({ apiKey, baseUrl }) => {
|
|
13797
14095
|
const { createOpenAI } = await import('@ai-sdk/openai');
|
|
@@ -13823,6 +14121,17 @@ var LOADERS = {
|
|
|
13823
14121
|
const { createMoonshotAI } = await import('@ai-sdk/moonshotai');
|
|
13824
14122
|
return createMoonshotAI({ apiKey });
|
|
13825
14123
|
},
|
|
14124
|
+
zhipu: openaiCompatibleFactory("zhipu", "https://open.bigmodel.cn/api/paas/v4"),
|
|
14125
|
+
dashscope: async ({ apiKey, baseUrl }) => {
|
|
14126
|
+
const { createAlibaba } = await import('@ai-sdk/alibaba');
|
|
14127
|
+
const provider = createAlibaba({
|
|
14128
|
+
apiKey,
|
|
14129
|
+
baseURL: baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
14130
|
+
});
|
|
14131
|
+
return (model) => provider.languageModel(model);
|
|
14132
|
+
},
|
|
14133
|
+
bytedance: openaiCompatibleFactory("bytedance", "https://ark.cn-beijing.volces.com/api/v3"),
|
|
14134
|
+
qianfan: openaiCompatibleFactory("qianfan", "https://qianfan.baidubce.com/v2"),
|
|
13826
14135
|
cohere: async ({ apiKey }) => {
|
|
13827
14136
|
const { createCohere } = await import('@ai-sdk/cohere');
|
|
13828
14137
|
return createCohere({ apiKey });
|
|
@@ -13851,15 +14160,7 @@ var LOADERS = {
|
|
|
13851
14160
|
const { createOllama } = await import('ollama-ai-provider-v2');
|
|
13852
14161
|
return createOllama();
|
|
13853
14162
|
},
|
|
13854
|
-
"openai-compatible":
|
|
13855
|
-
const { createOpenAICompatible } = await import('@ai-sdk/openai-compatible');
|
|
13856
|
-
return createOpenAICompatible({
|
|
13857
|
-
apiKey,
|
|
13858
|
-
baseURL: baseUrl || "http://localhost:8080/v1",
|
|
13859
|
-
name: "custom",
|
|
13860
|
-
includeUsage: true
|
|
13861
|
-
});
|
|
13862
|
-
}
|
|
14163
|
+
"openai-compatible": openaiCompatibleFactory("custom", "http://localhost:8080/v1")
|
|
13863
14164
|
};
|
|
13864
14165
|
var ProviderSdkMissingError = class extends Error {
|
|
13865
14166
|
constructor(providerType, packageName, cause) {
|
|
@@ -14491,6 +14792,10 @@ var STATIC_MODEL_CATALOG = {
|
|
|
14491
14792
|
],
|
|
14492
14793
|
mistral: ["mistral-large-latest", "mistral-small-latest", "codestral-latest"],
|
|
14493
14794
|
moonshotai: ["kimi-latest"],
|
|
14795
|
+
zhipu: ["glm-4.6", "glm-4.5-flash", "glm-4.5-air", "glm-4.5"],
|
|
14796
|
+
dashscope: ["qwen3-max", "qwen-plus", "qwen-flash", "qwen-turbo", "qwen-max-latest"],
|
|
14797
|
+
bytedance: ["doubao-seed-2.1-pro", "doubao-seed-2.0-mini", "doubao-seed-1.6-flash"],
|
|
14798
|
+
qianfan: ["ernie-5.0", "ernie-speed-128k", "ernie-4.0-turbo-8k"],
|
|
14494
14799
|
cohere: ["command-r-plus-04-2024", "command-r7b-12-2024", "command-a-03-2025"],
|
|
14495
14800
|
xai: ["grok-vision-beta"],
|
|
14496
14801
|
perplexity: ["sonar", "sonar-pro", "sonar-reasoning"],
|
|
@@ -14506,6 +14811,10 @@ var PROVIDER_DISCOVERY = {
|
|
|
14506
14811
|
groq: { baseUrl: "https://api.groq.com/openai/v1", auth: "bearer" },
|
|
14507
14812
|
mistral: { baseUrl: "https://api.mistral.ai/v1", auth: "bearer" },
|
|
14508
14813
|
moonshotai: { baseUrl: "https://api.moonshot.ai/v1", auth: "bearer" },
|
|
14814
|
+
zhipu: { baseUrl: "https://open.bigmodel.cn/api/paas/v4", auth: "bearer" },
|
|
14815
|
+
dashscope: { baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1", auth: "bearer" },
|
|
14816
|
+
bytedance: { baseUrl: "https://ark.cn-beijing.volces.com/api/v3", auth: "bearer" },
|
|
14817
|
+
qianfan: { baseUrl: "https://qianfan.baidubce.com/v2", auth: "bearer" },
|
|
14509
14818
|
xai: { baseUrl: "https://api.x.ai/v1", auth: "bearer" },
|
|
14510
14819
|
perplexity: { baseUrl: "https://api.perplexity.ai", auth: "bearer" },
|
|
14511
14820
|
togetherai: { baseUrl: "https://api.together.xyz/v1", auth: "bearer" }
|
|
@@ -14756,7 +15065,7 @@ function writeUserYaml(path, key, value) {
|
|
|
14756
15065
|
const after = asMapping(parseYaml(next));
|
|
14757
15066
|
const intact = after !== null && (dot < 0 ? onlyChanged(before, after, key, value) : onlyChangedNested(before, after, key.slice(0, dot), key.slice(dot + 1), value));
|
|
14758
15067
|
if (!intact) return { ok: false, reason: "unwritable-file" };
|
|
14759
|
-
return
|
|
15068
|
+
return commit(path, next, 384, value);
|
|
14760
15069
|
}
|
|
14761
15070
|
function writeSettingsJson(path, key, value) {
|
|
14762
15071
|
let before = {};
|
|
@@ -14776,7 +15085,7 @@ function writeSettingsJson(path, key, value) {
|
|
|
14776
15085
|
}
|
|
14777
15086
|
const body2 = `${JSON.stringify({ ...before, [key]: value }, null, 2)}
|
|
14778
15087
|
`;
|
|
14779
|
-
return
|
|
15088
|
+
return commit(path, body2, 420, value);
|
|
14780
15089
|
}
|
|
14781
15090
|
function scalarText(value) {
|
|
14782
15091
|
return dump(value, { lineWidth: -1 }).trimEnd();
|
|
@@ -14833,7 +15142,7 @@ function sameKeysAndValues(before, after, except) {
|
|
|
14833
15142
|
function sameData(a, b) {
|
|
14834
15143
|
return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
|
|
14835
15144
|
}
|
|
14836
|
-
function
|
|
15145
|
+
function commit(path, body2, createMode, value) {
|
|
14837
15146
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
14838
15147
|
try {
|
|
14839
15148
|
mkdirSync(dirname(path), { recursive: true });
|
|
@@ -18324,7 +18633,17 @@ function checkCodeExec(isolation) {
|
|
|
18324
18633
|
function checkAuto() {
|
|
18325
18634
|
return { allowed: true, code: "level-default" };
|
|
18326
18635
|
}
|
|
18327
|
-
function
|
|
18636
|
+
function outsideWorkspace(operation, extraRoots) {
|
|
18637
|
+
if (operation.type !== "file_read" && operation.type !== "file_write") return null;
|
|
18638
|
+
if (isInWorkspace(operation.target, operation.workDir, extraRoots)) return null;
|
|
18639
|
+
return {
|
|
18640
|
+
allowed: false,
|
|
18641
|
+
requireApproval: true,
|
|
18642
|
+
reason: t("permission_reason.outside_workspace"),
|
|
18643
|
+
code: "level-default"
|
|
18644
|
+
};
|
|
18645
|
+
}
|
|
18646
|
+
function checkPlan(operation, extraRoots) {
|
|
18328
18647
|
if (operation.type === "code_exec") {
|
|
18329
18648
|
return {
|
|
18330
18649
|
allowed: false,
|
|
@@ -18342,25 +18661,16 @@ function checkPlan(operation) {
|
|
|
18342
18661
|
code: "level-default"
|
|
18343
18662
|
};
|
|
18344
18663
|
}
|
|
18345
|
-
return { allowed: true, code: "level-default" };
|
|
18664
|
+
return outsideWorkspace(operation, extraRoots) ?? { allowed: true, code: "level-default" };
|
|
18346
18665
|
}
|
|
18347
18666
|
function checkAcceptEdits(operation, isolation, extraRoots) {
|
|
18348
18667
|
if (operation.type === "code_exec") return checkCodeExec(isolation);
|
|
18349
|
-
|
|
18350
|
-
if (isInWorkspace(operation.target, operation.workDir, extraRoots)) {
|
|
18351
|
-
return { allowed: true, code: "level-default" };
|
|
18352
|
-
}
|
|
18353
|
-
return {
|
|
18354
|
-
allowed: false,
|
|
18355
|
-
requireApproval: true,
|
|
18356
|
-
reason: t("permission_reason.outside_workspace"),
|
|
18357
|
-
code: "level-default"
|
|
18358
|
-
};
|
|
18359
|
-
}
|
|
18360
|
-
return { allowed: true, code: "level-default" };
|
|
18668
|
+
return outsideWorkspace(operation, extraRoots) ?? { allowed: true, code: "level-default" };
|
|
18361
18669
|
}
|
|
18362
|
-
function checkDefault(operation) {
|
|
18363
|
-
if (operation.type === "file_read")
|
|
18670
|
+
function checkDefault(operation, extraRoots) {
|
|
18671
|
+
if (operation.type === "file_read") {
|
|
18672
|
+
return outsideWorkspace(operation, extraRoots) ?? { allowed: true, code: "level-default" };
|
|
18673
|
+
}
|
|
18364
18674
|
if (operation.type === "command" && isReadOnlyCommand(operation.detail)) {
|
|
18365
18675
|
return { allowed: true, code: "level-default" };
|
|
18366
18676
|
}
|
|
@@ -18381,12 +18691,12 @@ function decideByLevel(level, operation, isolation, extraRoots = []) {
|
|
|
18381
18691
|
case "auto":
|
|
18382
18692
|
return checkAuto();
|
|
18383
18693
|
case "plan":
|
|
18384
|
-
return checkPlan(operation);
|
|
18694
|
+
return checkPlan(operation, extraRoots);
|
|
18385
18695
|
case "acceptEdits":
|
|
18386
18696
|
return checkAcceptEdits(operation, isolation, extraRoots);
|
|
18387
18697
|
case "default":
|
|
18388
18698
|
default:
|
|
18389
|
-
return checkDefault(operation);
|
|
18699
|
+
return checkDefault(operation, extraRoots);
|
|
18390
18700
|
}
|
|
18391
18701
|
}
|
|
18392
18702
|
var SENSITIVE_PATHS = [
|
|
@@ -19965,7 +20275,7 @@ function parseSimpleToml(content, file) {
|
|
|
19965
20275
|
const at = `${file}:${i + 1}`;
|
|
19966
20276
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
19967
20277
|
if (trimmed === "[[rule]]") {
|
|
19968
|
-
if (current)
|
|
20278
|
+
if (current) commit2(current, file, rules, issues);
|
|
19969
20279
|
current = { raw: {}, line: i + 1 };
|
|
19970
20280
|
continue;
|
|
19971
20281
|
}
|
|
@@ -19988,7 +20298,7 @@ function parseSimpleToml(content, file) {
|
|
|
19988
20298
|
current.raw[kv.key] = kv.value;
|
|
19989
20299
|
}
|
|
19990
20300
|
}
|
|
19991
|
-
if (current)
|
|
20301
|
+
if (current) commit2(current, file, rules, issues);
|
|
19992
20302
|
return { rules, issues };
|
|
19993
20303
|
}
|
|
19994
20304
|
function readKeyValue(line) {
|
|
@@ -20002,7 +20312,7 @@ function readKeyValue(line) {
|
|
|
20002
20312
|
const sq = rawVal.match(/^'(.*)'$/);
|
|
20003
20313
|
return { key, value: sq && sq[1] ? sq[1] : rawVal };
|
|
20004
20314
|
}
|
|
20005
|
-
function
|
|
20315
|
+
function commit2(draft, file, rules, issues) {
|
|
20006
20316
|
const at = `${file}:${draft.line}`;
|
|
20007
20317
|
issues.push(...unknownKeyIssues(POLICY_RULE_KEYS, draft.raw, at));
|
|
20008
20318
|
const raw = { ...draft.raw };
|
|
@@ -20913,14 +21223,14 @@ function runCommandHook(config, event, workDir) {
|
|
|
20913
21223
|
const baseEnv = sanitizeEnvironment(process.env);
|
|
20914
21224
|
const injectedEnv = injectEpochEnv(event, config.pluginRoot);
|
|
20915
21225
|
const hookEnv = { ...baseEnv, ...injectedEnv, ...config.env };
|
|
20916
|
-
return new Promise((
|
|
21226
|
+
return new Promise((resolve17) => {
|
|
20917
21227
|
let stdout = "";
|
|
20918
21228
|
let stderr = "";
|
|
20919
21229
|
let settled = false;
|
|
20920
21230
|
const failToStart = (err) => {
|
|
20921
21231
|
if (settled) return;
|
|
20922
21232
|
settled = true;
|
|
20923
|
-
|
|
21233
|
+
resolve17({
|
|
20924
21234
|
exitCode: -1,
|
|
20925
21235
|
stdout,
|
|
20926
21236
|
stderr,
|
|
@@ -20942,7 +21252,7 @@ function runCommandHook(config, event, workDir) {
|
|
|
20942
21252
|
if (!settled) {
|
|
20943
21253
|
settled = true;
|
|
20944
21254
|
child.kill("SIGKILL");
|
|
20945
|
-
|
|
21255
|
+
resolve17({
|
|
20946
21256
|
exitCode: -1,
|
|
20947
21257
|
stdout,
|
|
20948
21258
|
stderr,
|
|
@@ -20978,7 +21288,7 @@ function runCommandHook(config, event, workDir) {
|
|
|
20978
21288
|
}
|
|
20979
21289
|
} catch {
|
|
20980
21290
|
}
|
|
20981
|
-
|
|
21291
|
+
resolve17({
|
|
20982
21292
|
exitCode,
|
|
20983
21293
|
stdout: stdout.trim(),
|
|
20984
21294
|
stderr: stderr.trim(),
|
|
@@ -22490,7 +22800,7 @@ async function importSkills(source, opts) {
|
|
|
22490
22800
|
detail: t("skill.import_stale", void 0, opts.lang)
|
|
22491
22801
|
};
|
|
22492
22802
|
}
|
|
22493
|
-
return { ok: true, ...
|
|
22803
|
+
return { ok: true, ...commit3(preview3, staged, opts.skillsDir, opts.lang) };
|
|
22494
22804
|
});
|
|
22495
22805
|
}
|
|
22496
22806
|
async function withStaged(source, opts, fn) {
|
|
@@ -22609,7 +22919,7 @@ function digest(entries2, staged) {
|
|
|
22609
22919
|
}
|
|
22610
22920
|
return hash.digest("hex").slice(0, 32);
|
|
22611
22921
|
}
|
|
22612
|
-
function
|
|
22922
|
+
function commit3(preview3, staged, skillsDir, lang) {
|
|
22613
22923
|
const byName = new Map(staged.map((s) => [s.name, s.dir]));
|
|
22614
22924
|
const imported = [];
|
|
22615
22925
|
const skipped = [];
|
|
@@ -23761,7 +24071,7 @@ var CodeSandbox = class {
|
|
|
23761
24071
|
stdio: ["ignore", "pipe", "pipe"],
|
|
23762
24072
|
...IS_WINDOWS ? { windowsHide: true } : {}
|
|
23763
24073
|
};
|
|
23764
|
-
return new Promise((
|
|
24074
|
+
return new Promise((resolve17) => {
|
|
23765
24075
|
let stdout = "";
|
|
23766
24076
|
let stderr = "";
|
|
23767
24077
|
let killedForOutput = false;
|
|
@@ -23772,7 +24082,7 @@ var CodeSandbox = class {
|
|
|
23772
24082
|
const failToStart = (err) => {
|
|
23773
24083
|
opts.signal?.removeEventListener("abort", onAbort);
|
|
23774
24084
|
if (err.code === "ENOENT") {
|
|
23775
|
-
|
|
24085
|
+
resolve17({
|
|
23776
24086
|
success: false,
|
|
23777
24087
|
output: "",
|
|
23778
24088
|
error: `[\u9519\u8BEF] \u627E\u4E0D\u5230\u89E3\u91CA\u5668: ${command}`,
|
|
@@ -23781,7 +24091,7 @@ var CodeSandbox = class {
|
|
|
23781
24091
|
});
|
|
23782
24092
|
return;
|
|
23783
24093
|
}
|
|
23784
|
-
|
|
24094
|
+
resolve17({
|
|
23785
24095
|
success: false,
|
|
23786
24096
|
output: "",
|
|
23787
24097
|
error: `[\u9519\u8BEF] ${err.message}\uFF08command=${command}\uFF0Ccwd=${spawnOpts.cwd ?? ""}\uFF09`,
|
|
@@ -23817,7 +24127,7 @@ var CodeSandbox = class {
|
|
|
23817
24127
|
if (stderr.length < MAX_OUTPUT) stderr += errDecoder?.end() ?? "";
|
|
23818
24128
|
const duration = Date.now() - start;
|
|
23819
24129
|
if (killedForOutput) {
|
|
23820
|
-
|
|
24130
|
+
resolve17({
|
|
23821
24131
|
success: false,
|
|
23822
24132
|
output: trunc(stdout, stderr),
|
|
23823
24133
|
error: `[\u8F93\u51FA\u8D85\u9650] \u8D85\u8FC7 ${MAX_OUTPUT} \u5B57\u8282\uFF0C\u5DF2\u7EC8\u6B62`,
|
|
@@ -23827,7 +24137,7 @@ var CodeSandbox = class {
|
|
|
23827
24137
|
return;
|
|
23828
24138
|
}
|
|
23829
24139
|
if (sig) {
|
|
23830
|
-
|
|
24140
|
+
resolve17({
|
|
23831
24141
|
success: false,
|
|
23832
24142
|
output: trunc(stdout, stderr),
|
|
23833
24143
|
error: opts.signal?.aborted ? "[\u5DF2\u53D6\u6D88]" : "[\u8D85\u65F6] \u6267\u884C\u8D85\u65F6",
|
|
@@ -23839,7 +24149,7 @@ var CodeSandbox = class {
|
|
|
23839
24149
|
const output = trunc(stdout, stderr);
|
|
23840
24150
|
if (code !== 0 && code !== null) {
|
|
23841
24151
|
const oom = /heap out of memory|allocation failed/i.test(stderr);
|
|
23842
|
-
|
|
24152
|
+
resolve17({
|
|
23843
24153
|
success: false,
|
|
23844
24154
|
output,
|
|
23845
24155
|
error: oom ? `[\u5185\u5B58\u8D85\u9650] \u8D85\u8FC7 ${MAX_MEMORY}MB` : `[\u8FD0\u884C\u65F6\u9519\u8BEF] exit ${code}: ${stderr.slice(0, 200)}`,
|
|
@@ -23848,7 +24158,7 @@ var CodeSandbox = class {
|
|
|
23848
24158
|
});
|
|
23849
24159
|
return;
|
|
23850
24160
|
}
|
|
23851
|
-
|
|
24161
|
+
resolve17({ success: true, output, duration });
|
|
23852
24162
|
});
|
|
23853
24163
|
});
|
|
23854
24164
|
}
|
|
@@ -23908,4 +24218,4 @@ function trunc(stdout, stderr) {
|
|
|
23908
24218
|
* `--tree` 的命令帮助里,让用户自己知道 `--tree` 意味着什么。
|
|
23909
24219
|
*/
|
|
23910
24220
|
|
|
23911
|
-
export { AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, ATTACHMENT_MAX_TOTAL_BYTES, ATTACHMENT_RETENTION_DEFAULTS, AgentLoop, AppearanceStore, ApprovalCache, BLOCKED_TOOLS, BudgetGuard, BudgetStore, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, CheckpointManager, CheckpointStore, CodeSandbox, ComplianceEngine, ContextCompressor, DEFAULT_COMPLIANCE_ACTIONS, DEFAULT_COMPLIANCE_SETTINGS, DEFAULT_COMPRESSION_THRESHOLD, DEFAULT_GOAL_MAX_ROUNDS, DEFAULT_MAX_HOLD_CHARS, DelegateManager, EMPTY_RULES, EPOCH_DISK_LEDGER, EpochConfigSchema, FTS_TABLES, FTS_TRIGGERS, GOAL_BLOCK_CODES, GoalService, GoalStore, HEADLESS_AUDIT_CODES, HookManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, ImageLoadError, ImportTrustStore, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, LastOpenSessions, MARKETPLACE_DISPLAY_FIELDS, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_LAST_OPEN_SESSIONS, MAX_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, ManagedPolicyError, ManagedSettingsSchema, MemoryManager, ModelFailureTracker, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, PACK_EXCLUDES, PACK_MAX_BYTES, PACK_MAX_FILES, PERMISSION_AUDIT_CODES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_MANIFEST_KEYS, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, PLUGIN_VISIBILITY, POLICY_DECISIONS, PROBE_VERSION, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, PermissionManager, PlanModeState, PluginAuthorSchema, PluginStore, PolicyRuleSchema, ProviderError, ProviderRouter, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, RecentWorkspaces, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_FORM_BUDGET_USD, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, SKILL_PATCH_TOOL, SKILL_VIEW_TOOL, SKILL_WRITE_FILE_TOOL, SLASH_COMMANDS_DIAG_MODULE, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, SessionManager, SessionQueries, SessionReferences, SettingsFileError, SettingsFileSchema, SkillLearner, SkillSystem, TOOL_SEARCH_TOOL, TaskNoticeTracker, ToolRegistry, TrackerDB, TrustManager, Workspace, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, checkEpochVersion, checkFtsHealth, checkShadowing, classifyPersistFailure, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, computeExecHash, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, defaultModelOf, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, displayAllows, displayCurrency, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, extractArchive, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, hasDedicatedExecContent, hasExecTierContent, hasPromptCaching, hasProviderCredentials, hasReadTierContent, imageFromBase64, imageFromPath, imagePartTokens, importParts, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryProjectExtensions, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isTransientPersistFailure, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listRunningSchedules, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelListCandidates, needsAllowlist, nextFallbackModel, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, openArtifact, originOf, packFileName, packPlugin, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistFailureCode, persistParts, persistToolResults, persistedUsage, planPack, previewSkillImport, pricingFor, projectEntryForDisplay, pruneArtifacts, pruneAttachments, pruneRecordings, pruneSchedules, readImageSize, readMarketplaces, readPluginManifest, readPluginRecords, readProviderKeyEnv, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeRecordings, removeRoleFile, removeSessionArtifacts, removeSessionAttachments, renderImportTree, renderProjectContext, renderSdkDeclaration, renderSelfIndex, repairSchedules, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolvePricingAt, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveTar, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand2 as runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setDisplayCurrency, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteApply, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writeSettingValue };
|
|
24221
|
+
export { AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, ATTACHMENT_MAX_TOTAL_BYTES, ATTACHMENT_RETENTION_DEFAULTS, AgentLoop, AppearanceStore, ApprovalCache, BLOCKED_TOOLS, BudgetGuard, BudgetStore, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, CheckpointManager, CheckpointStore, CodeSandbox, ComplianceEngine, ContextCompressor, DEFAULT_COMPLIANCE_ACTIONS, DEFAULT_COMPLIANCE_SETTINGS, DEFAULT_COMPRESSION_THRESHOLD, DEFAULT_GOAL_MAX_ROUNDS, DEFAULT_MAX_HOLD_CHARS, DelegateManager, EMPTY_RULES, EPOCH_DISK_LEDGER, EpochConfigSchema, FTS_TABLES, FTS_TRIGGERS, GOAL_BLOCK_CODES, GoalService, GoalStore, HEADLESS_AUDIT_CODES, HookManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, ImageLoadError, ImportTrustStore, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, LastOpenSessions, MARKETPLACE_DISPLAY_FIELDS, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_LAST_OPEN_SESSIONS, MAX_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, ManagedPolicyError, ManagedSettingsSchema, MemoryManager, ModelFailureTracker, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, PACK_EXCLUDES, PACK_MAX_BYTES, PACK_MAX_FILES, PERMISSION_AUDIT_CODES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_MANIFEST_KEYS, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, PLUGIN_VISIBILITY, POLICY_DECISIONS, PROBE_VERSION, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, PermissionManager, PlanModeState, PluginAuthorSchema, PluginStore, PolicyRuleSchema, ProviderError, ProviderRouter, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, RecentWorkspaces, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_FORM_BUDGET_USD, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, SKILL_PATCH_TOOL, SKILL_VIEW_TOOL, SKILL_WRITE_FILE_TOOL, SLASH_COMMANDS_DIAG_MODULE, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, SessionManager, SessionQueries, SessionReferences, SettingsFileError, SettingsFileSchema, SkillLearner, SkillSystem, TOOL_SEARCH_TOOL, TaskNoticeTracker, ToolRegistry, TrackerDB, TrustManager, Workspace, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, approvalEntryFor, approvalRootFor, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, checkEpochVersion, checkFtsHealth, checkShadowing, classifyPersistFailure, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, computeExecHash, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, defaultModelOf, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, displayAllows, displayCurrency, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, extractArchive, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, grantedPathsFor, hasDedicatedExecContent, hasExecTierContent, hasPromptCaching, hasProviderCredentials, hasReadTierContent, imageFromBase64, imageFromPath, imagePartTokens, importParts, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryProjectExtensions, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isTransientPersistFailure, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listRunningSchedules, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelListCandidates, needsAllowlist, nextFallbackModel, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, openArtifact, originOf, packFileName, packPlugin, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistFailureCode, persistParts, persistToolResults, persistedUsage, planPack, previewSkillImport, pricingFor, projectEntryForDisplay, pruneArtifacts, pruneAttachments, pruneRecordings, pruneSchedules, readImageSize, readMarketplaces, readPluginManifest, readPluginRecords, readProviderKeyEnv, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeRecordings, removeRoleFile, removeSessionArtifacts, removeSessionAttachments, renderImportTree, renderProjectContext, renderSdkDeclaration, renderSelfIndex, repairSchedules, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolvePricingAt, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveTar, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand2 as runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setDisplayCurrency, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteApply, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writeSettingValue };
|