@epoch-agent/core 0.20.1 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/index.d.ts +220 -2
- package/dist/index.js +1013 -672
- 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, isInWorkspace, workspacesPath, samePath, lastSessionsPath, 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';
|
|
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, isInWorkspace, 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';
|
|
@@ -274,7 +274,7 @@ function createLaunchdBackend(opts = {}) {
|
|
|
274
274
|
mkdirSync(input.logDir, { recursive: true });
|
|
275
275
|
writeFileSync(path, renderPlist(label, input), "utf-8");
|
|
276
276
|
} catch (err) {
|
|
277
|
-
return { ok: false, detail: `plist-write-failed: ${
|
|
277
|
+
return { ok: false, detail: `plist-write-failed: ${describe9(err)}` };
|
|
278
278
|
}
|
|
279
279
|
await run("launchctl", ["bootout", `${guiDomain()}/${label}`]);
|
|
280
280
|
const toggle = await backend.setEnabled(label, input.enabled);
|
|
@@ -290,7 +290,7 @@ function createLaunchdBackend(opts = {}) {
|
|
|
290
290
|
try {
|
|
291
291
|
rmSync(plistPath(label), { force: true });
|
|
292
292
|
} catch (err) {
|
|
293
|
-
return { ok: false, detail: `plist-remove-failed: ${
|
|
293
|
+
return { ok: false, detail: `plist-remove-failed: ${describe9(err)}` };
|
|
294
294
|
}
|
|
295
295
|
return { ok: true };
|
|
296
296
|
},
|
|
@@ -447,7 +447,7 @@ function detailOf2(what, res) {
|
|
|
447
447
|
const msg = (res.stderr || res.stdout).trim();
|
|
448
448
|
return `${what} exit ${res.code}${msg ? `: ${msg}` : ""}`;
|
|
449
449
|
}
|
|
450
|
-
function
|
|
450
|
+
function describe9(err) {
|
|
451
451
|
return err instanceof Error ? err.message : String(err);
|
|
452
452
|
}
|
|
453
453
|
var LAUNCHD_LABEL_PREFIX;
|
|
@@ -650,7 +650,7 @@ var ToolRegistry = class {
|
|
|
650
650
|
this.addTool(tool, source);
|
|
651
651
|
}
|
|
652
652
|
registerTools(tools, source = "builtin") {
|
|
653
|
-
for (const
|
|
653
|
+
for (const t81 of tools) this.addTool(t81, source);
|
|
654
654
|
}
|
|
655
655
|
addTool(tool, source) {
|
|
656
656
|
const existing = this.tools.get(tool.name);
|
|
@@ -699,14 +699,14 @@ var ToolRegistry = class {
|
|
|
699
699
|
return isCodeModeDeferred(tool) ? ToolExposure.Deferred : declared;
|
|
700
700
|
}
|
|
701
701
|
exposed() {
|
|
702
|
-
return this.list().filter((
|
|
702
|
+
return this.list().filter((t81) => this.exposureOf(t81) === ToolExposure.Direct);
|
|
703
703
|
}
|
|
704
704
|
byExposure(exposure) {
|
|
705
|
-
return this.list().filter((
|
|
705
|
+
return this.list().filter((t81) => this.exposureOf(t81) === exposure);
|
|
706
706
|
}
|
|
707
707
|
codeModeDeclared() {
|
|
708
708
|
if (!this.codeMode) return [];
|
|
709
|
-
return this.list().filter((
|
|
709
|
+
return this.list().filter((t81) => isCodeModeDeferred(t81));
|
|
710
710
|
}
|
|
711
711
|
sourceOf(name) {
|
|
712
712
|
return this.tools.get(name)?.source;
|
|
@@ -755,7 +755,7 @@ var ToolRegistry = class {
|
|
|
755
755
|
function staticToolProvider(tools) {
|
|
756
756
|
return {
|
|
757
757
|
list: () => tools,
|
|
758
|
-
get: (name) => tools.find((
|
|
758
|
+
get: (name) => tools.find((t81) => t81.name === name)
|
|
759
759
|
};
|
|
760
760
|
}
|
|
761
761
|
var log = createLogger("tokenizer");
|
|
@@ -861,6 +861,21 @@ function parseOption(raw) {
|
|
|
861
861
|
const description = typeof raw["description"] === "string" ? raw["description"].trim() : "";
|
|
862
862
|
return { label, description };
|
|
863
863
|
}
|
|
864
|
+
function parsePage(raw) {
|
|
865
|
+
if (!isRecord(raw)) return void 0;
|
|
866
|
+
const rawUrl = typeof raw["url"] === "string" ? raw["url"].trim() : "";
|
|
867
|
+
if (!rawUrl) return void 0;
|
|
868
|
+
let url;
|
|
869
|
+
try {
|
|
870
|
+
url = new URL(rawUrl);
|
|
871
|
+
} catch {
|
|
872
|
+
return void 0;
|
|
873
|
+
}
|
|
874
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
|
|
875
|
+
if (url.hostname !== "127.0.0.1" && url.hostname !== "localhost") return void 0;
|
|
876
|
+
const label = typeof raw["label"] === "string" ? raw["label"].trim() : "";
|
|
877
|
+
return label ? { url: rawUrl, label } : { url: rawUrl };
|
|
878
|
+
}
|
|
864
879
|
function parseQuestion(raw, at) {
|
|
865
880
|
if (!isRecord(raw)) return `questions[${at}] \u4E0D\u662F\u5BF9\u8C61`;
|
|
866
881
|
const question = typeof raw["question"] === "string" ? raw["question"].trim() : "";
|
|
@@ -878,11 +893,13 @@ function parseQuestion(raw, at) {
|
|
|
878
893
|
if (options.length < MIN_OPTIONS || options.length > MAX_OPTIONS) {
|
|
879
894
|
return `questions[${at}] \u6709 ${options.length} \u4E2A\u9009\u9879\uFF0C\u8981 ${MIN_OPTIONS}\u2013${MAX_OPTIONS} \u4E2A\u3002**\u4E0D\u8981**\u81EA\u5DF1\u52A0\u300C\u5176\u4ED6\u300D\u9009\u9879 \u2014\u2014 \u81EA\u7531\u8F93\u5165\u7531\u754C\u9762\u81EA\u52A8\u63D0\u4F9B`;
|
|
880
895
|
}
|
|
896
|
+
const page = parsePage(raw["page"]);
|
|
881
897
|
return {
|
|
882
898
|
question,
|
|
883
899
|
header,
|
|
884
900
|
options,
|
|
885
|
-
multiSelect: raw["multiSelect"] === true
|
|
901
|
+
multiSelect: raw["multiSelect"] === true,
|
|
902
|
+
...page ? { page } : {}
|
|
886
903
|
};
|
|
887
904
|
}
|
|
888
905
|
function parseQuestions(raw) {
|
|
@@ -957,7 +974,19 @@ var PARAMETERS = {
|
|
|
957
974
|
required: ["label", "description"]
|
|
958
975
|
}
|
|
959
976
|
},
|
|
960
|
-
multiSelect: { type: "boolean", description: "\u80FD\u4E0D\u80FD\u591A\u9009\u3002\u9ED8\u8BA4 false" }
|
|
977
|
+
multiSelect: { type: "boolean", description: "\u80FD\u4E0D\u80FD\u591A\u9009\u3002\u9ED8\u8BA4 false" },
|
|
978
|
+
page: {
|
|
979
|
+
type: "object",
|
|
980
|
+
description: "\u8FD9\u4E00\u95EE\u8FD8\u53EF\u4EE5\u5D4C\u4E00\u5F20\u63D2\u4EF6\u9875\u9762\uFF08\u53EA\u5728\u5E26\u754C\u9762\u7684\u5BBF\u4E3B\u91CC\u6709 \u2014\u2014 \u7EC8\u7AEF\u91CC\u4F1A\u88AB\u8BF4\u6210\u4E00\u53E5\u8BDD\uFF0C\u7528\u6237\u81EA\u5DF1\u5F00\uFF09\u3002\u26A0\uFE0F url \u53EA\u6536\u672C\u673A\u56DE\u73AF\uFF08127.0.0.1 / localhost\uFF09\uFF0C\u522B\u7684\u4F1A\u88AB\u4E22\u6389",
|
|
981
|
+
properties: {
|
|
982
|
+
url: {
|
|
983
|
+
type: "string",
|
|
984
|
+
description: "\u90A3\u4E00\u9875\u7684\u5730\u5740\uFF0C\u5F62\u5982 http://127.0.0.1:52341/confirm?t=\u2026"
|
|
985
|
+
},
|
|
986
|
+
label: { type: "string", description: "\u9875\u9762\u4E0A\u90A3\u51E0\u4E2A\u5B57\u3002\u4E0D\u7ED9\u5C31\u7528\u4E00\u53E5\u901A\u7528\u6587\u6848" }
|
|
987
|
+
},
|
|
988
|
+
required: ["url"]
|
|
989
|
+
}
|
|
961
990
|
},
|
|
962
991
|
required: ["question", "header", "options", "multiSelect"]
|
|
963
992
|
}
|
|
@@ -972,7 +1001,10 @@ var DESCRIPTION = [
|
|
|
972
1001
|
"**\u6709\u660E\u663E\u9ED8\u8BA4\u7B54\u6848\u65F6\u4E0D\u8981\u95EE**\uFF0C\u76F4\u63A5\u505A\u5E76\u8BF4\u660E \u2014\u2014 \u4ED3\u5E93\u91CC\u5DF2\u7ECF\u6709 vitest.config \u7684\u65F6\u5019",
|
|
973
1002
|
"\u300C\u7528\u54EA\u4E2A\u6D4B\u8BD5\u6846\u67B6\u300D\u4E0D\u662F\u4E00\u4E2A\u95EE\u9898\u3002",
|
|
974
1003
|
"\u4E0D\u8981\u7528\u5B83\u95EE\u300C\u6211\u7684\u65B9\u6848\u884C\u4E0D\u884C\u300D\uFF08\u90A3\u662F exit_plan_mode\uFF09\uFF0C\u4E5F\u4E0D\u8981\u7528\u5B83\u6C47\u62A5\u8FDB\u5EA6\u3002",
|
|
975
|
-
"\u9009\u9879\u91CC**\u4E0D\u8981**\u81EA\u5DF1\u653E\u300C\u5176\u4ED6\u300D\uFF1A\u754C\u9762\u4F1A\u81EA\u52A8\u63D0\u4F9B\u81EA\u7531\u8F93\u5165\u3002"
|
|
1004
|
+
"\u9009\u9879\u91CC**\u4E0D\u8981**\u81EA\u5DF1\u653E\u300C\u5176\u4ED6\u300D\uFF1A\u754C\u9762\u4F1A\u81EA\u52A8\u63D0\u4F9B\u81EA\u7531\u8F93\u5165\u3002",
|
|
1005
|
+
"\u26A0\uFE0F \u63D2\u4EF6\u7684\u5DE5\u5177\u7ED9\u4E86\u4F60\u4E00\u4E2A**\u672C\u673A\u5730\u5740**\u3001\u800C\u90A3\u4E2A\u9009\u62E9\u7528\u51E0\u4E2A\u9009\u9879\u8BF4\u4E0D\u6E05\u65F6\uFF08\u51E0\u5341\u5F20\u56FE\u91CC\u6311\u4E00\u5F20\u3001",
|
|
1006
|
+
"\u4E00\u5F20\u8868\u91CC\u5708\u51E0\u884C\uFF09\uFF0C\u628A\u5730\u5740\u653E\u8FDB `questions[].page` \u2014\u2014 \u7528\u6237\u4F1A\u5728\u5F39\u7A97\u91CC\u76F4\u63A5\u770B\u5230\u90A3\u4E00\u9875\u3002",
|
|
1007
|
+
"\u5B83**\u9644\u52A0\u5728\u9009\u9879\u4E4B\u5916**\uFF0C\u9009\u9879\u7167\u65E7\u8981\u7ED9\uFF1A\u7EC8\u7AEF\u91CC\u753B\u4E0D\u51FA\u9875\u9762\uFF0C\u90A3\u65F6\u7528\u6237\u770B\u5230\u7684\u53EA\u6709\u4F60\u5199\u7684\u9009\u9879\u3002"
|
|
976
1008
|
].join("");
|
|
977
1009
|
function createAskQuestionTool(deps) {
|
|
978
1010
|
return {
|
|
@@ -1388,7 +1420,7 @@ var DelegateManager = class {
|
|
|
1388
1420
|
}
|
|
1389
1421
|
normalizeTasks(args) {
|
|
1390
1422
|
if (args.tasks && args.tasks.length > 0) {
|
|
1391
|
-
return args.role ? args.tasks.map((
|
|
1423
|
+
return args.role ? args.tasks.map((t81) => ({ ...t81, role: t81.role ?? args.role })) : args.tasks;
|
|
1392
1424
|
}
|
|
1393
1425
|
if (args.goal) return [{ goal: args.goal, ...args.role ? { role: args.role } : {} }];
|
|
1394
1426
|
return [];
|
|
@@ -1398,7 +1430,7 @@ var DelegateManager = class {
|
|
|
1398
1430
|
for (let i = 0; i < tasks.length; i += maxConcurrent) {
|
|
1399
1431
|
const batch = tasks.slice(i, i + maxConcurrent);
|
|
1400
1432
|
const batchResults = await Promise.allSettled(
|
|
1401
|
-
batch.map((
|
|
1433
|
+
batch.map((t81) => this.runSingleTask(t81, parentSessionId, signal))
|
|
1402
1434
|
);
|
|
1403
1435
|
for (const r of batchResults) {
|
|
1404
1436
|
if (r.status === "fulfilled") {
|
|
@@ -1556,21 +1588,21 @@ function createDelegateTool(runner, config, roles) {
|
|
|
1556
1588
|
operation: "command",
|
|
1557
1589
|
describeTarget: (args) => {
|
|
1558
1590
|
const tasks = Array.isArray(args["tasks"]) ? args["tasks"] : [];
|
|
1559
|
-
const goals = tasks.map((
|
|
1591
|
+
const goals = tasks.map((t81) => String(t81["goal"] ?? ""));
|
|
1560
1592
|
const single = typeof args["goal"] === "string" ? args["goal"] : "";
|
|
1561
1593
|
return [...goals, single].filter(Boolean).join(" | ");
|
|
1562
1594
|
},
|
|
1563
1595
|
async execute(args, ctx) {
|
|
1564
1596
|
const start = Date.now();
|
|
1565
1597
|
const rawTasks = Array.isArray(args["tasks"]) ? args["tasks"] : void 0;
|
|
1566
|
-
const tasks = rawTasks?.map((
|
|
1567
|
-
const o =
|
|
1598
|
+
const tasks = rawTasks?.map((t81) => {
|
|
1599
|
+
const o = t81;
|
|
1568
1600
|
return {
|
|
1569
1601
|
goal: String(o["goal"] ?? "").trim(),
|
|
1570
1602
|
context: String(o["context"] ?? ""),
|
|
1571
1603
|
...typeof o["role"] === "string" && o["role"].trim() ? { role: o["role"].trim() } : {}
|
|
1572
1604
|
};
|
|
1573
|
-
}).filter((
|
|
1605
|
+
}).filter((t81) => t81.goal.length > 0);
|
|
1574
1606
|
const goal = typeof args["goal"] === "string" ? args["goal"].trim() : "";
|
|
1575
1607
|
const topRole = typeof args["role"] === "string" ? args["role"].trim() : "";
|
|
1576
1608
|
if ((!tasks || tasks.length === 0) && !goal) {
|
|
@@ -1586,7 +1618,7 @@ function createDelegateTool(runner, config, roles) {
|
|
|
1586
1618
|
};
|
|
1587
1619
|
}
|
|
1588
1620
|
const known = listRoles();
|
|
1589
|
-
const requested = [...(tasks ?? []).map((
|
|
1621
|
+
const requested = [...(tasks ?? []).map((t81) => t81.role), topRole].filter(
|
|
1590
1622
|
(r) => Boolean(r)
|
|
1591
1623
|
);
|
|
1592
1624
|
const unknown = [...new Set(requested)].filter((r) => !known.some((k) => k.name === r));
|
|
@@ -1760,8 +1792,8 @@ function createGoalTool(deps) {
|
|
|
1760
1792
|
}
|
|
1761
1793
|
var VALID_TARGETS = ["memory", "user"];
|
|
1762
1794
|
var VALID_ACTIONS = ["add", "replace", "remove", "search", "read", "budget"];
|
|
1763
|
-
function isValidTarget(
|
|
1764
|
-
return typeof
|
|
1795
|
+
function isValidTarget(t81) {
|
|
1796
|
+
return typeof t81 === "string" && VALID_TARGETS.includes(t81);
|
|
1765
1797
|
}
|
|
1766
1798
|
function isValidAction(a) {
|
|
1767
1799
|
return VALID_ACTIONS.includes(a);
|
|
@@ -4915,7 +4947,7 @@ function available(tools) {
|
|
|
4915
4947
|
if (tools.length === 0) {
|
|
4916
4948
|
return "No deferred tools in this session \u2014 every tool is already in your tool list.";
|
|
4917
4949
|
}
|
|
4918
|
-
const names = tools.map((
|
|
4950
|
+
const names = tools.map((t81) => t81.name).sort();
|
|
4919
4951
|
const shown = names.slice(0, MAX_LISTED);
|
|
4920
4952
|
const rest = names.length - shown.length;
|
|
4921
4953
|
return `Searchable tools: ${shown.join(", ")}${rest > 0 ? ` (\u2026and ${rest} more)` : ""}.`;
|
|
@@ -5035,15 +5067,15 @@ var TrackerDB = class {
|
|
|
5035
5067
|
);
|
|
5036
5068
|
this.db.transaction(() => {
|
|
5037
5069
|
this.db.prepare("DELETE FROM todos WHERE session_id = ?").run(sessionId);
|
|
5038
|
-
for (const
|
|
5070
|
+
for (const t81 of todos) {
|
|
5039
5071
|
insertStmt.run({
|
|
5040
|
-
id:
|
|
5072
|
+
id: t81.id,
|
|
5041
5073
|
session_id: sessionId,
|
|
5042
|
-
content:
|
|
5043
|
-
status:
|
|
5044
|
-
reason:
|
|
5045
|
-
created_at:
|
|
5046
|
-
updated_at:
|
|
5074
|
+
content: t81.content,
|
|
5075
|
+
status: t81.status,
|
|
5076
|
+
reason: t81.reason || null,
|
|
5077
|
+
created_at: t81.created_at,
|
|
5078
|
+
updated_at: t81.updated_at
|
|
5047
5079
|
});
|
|
5048
5080
|
}
|
|
5049
5081
|
})();
|
|
@@ -5065,9 +5097,9 @@ function formatTodoList(todos, pendingCount) {
|
|
|
5065
5097
|
cancelled: "\u5DF2\u53D6\u6D88"
|
|
5066
5098
|
};
|
|
5067
5099
|
lines.push(`[todo] \u72B6\u6001\u6C47\u603B: ${pendingCount} \u4E2A\u5F85\u5B8C\u6210`);
|
|
5068
|
-
for (const
|
|
5069
|
-
const label = statusLabel[
|
|
5070
|
-
lines.push(`- [${label}] ${
|
|
5100
|
+
for (const t81 of todos) {
|
|
5101
|
+
const label = statusLabel[t81.status] || t81.status;
|
|
5102
|
+
lines.push(`- [${label}] ${t81.content}${t81.reason ? ` \u2014\u2014 ${t81.reason}` : ""}`);
|
|
5071
5103
|
}
|
|
5072
5104
|
return lines.join("\n");
|
|
5073
5105
|
}
|
|
@@ -5141,14 +5173,14 @@ function createTodoTool(db) {
|
|
|
5141
5173
|
};
|
|
5142
5174
|
}
|
|
5143
5175
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5144
|
-
const existing = new Map(db.listBySession(ctx.sessionId).map((
|
|
5145
|
-
const todos = rawTodos.map((
|
|
5146
|
-
const prev =
|
|
5147
|
-
const status = isValidStatus(
|
|
5148
|
-
const reason9 = normalizeReason(status,
|
|
5176
|
+
const existing = new Map(db.listBySession(ctx.sessionId).map((t81) => [t81.id, t81]));
|
|
5177
|
+
const todos = rawTodos.map((t81) => {
|
|
5178
|
+
const prev = t81.id ? existing.get(t81.id) : void 0;
|
|
5179
|
+
const status = isValidStatus(t81.status) ? t81.status : "pending";
|
|
5180
|
+
const reason9 = normalizeReason(status, t81.reason);
|
|
5149
5181
|
return {
|
|
5150
|
-
id:
|
|
5151
|
-
content: String(
|
|
5182
|
+
id: t81.id || generateShortId(),
|
|
5183
|
+
content: String(t81.content || "").slice(0, 500),
|
|
5152
5184
|
status,
|
|
5153
5185
|
...reason9 ? { reason: reason9 } : {},
|
|
5154
5186
|
created_at: prev?.created_at || now,
|
|
@@ -5156,7 +5188,7 @@ function createTodoTool(db) {
|
|
|
5156
5188
|
};
|
|
5157
5189
|
});
|
|
5158
5190
|
db.replaceAll(ctx.sessionId, todos);
|
|
5159
|
-
const pendingCount = todos.filter((
|
|
5191
|
+
const pendingCount = todos.filter((t81) => isOpenTodo(t81.status)).length;
|
|
5160
5192
|
return {
|
|
5161
5193
|
success: true,
|
|
5162
5194
|
output: formatTodoList(todos, pendingCount),
|
|
@@ -5491,7 +5523,7 @@ function intersectNames(base, incoming) {
|
|
|
5491
5523
|
if (!base) return incoming ? [...incoming] : void 0;
|
|
5492
5524
|
if (!incoming) return [...base];
|
|
5493
5525
|
const baseSet = new Set(base);
|
|
5494
|
-
return incoming.filter((
|
|
5526
|
+
return incoming.filter((t81) => baseSet.has(t81));
|
|
5495
5527
|
}
|
|
5496
5528
|
function findRole(roles, name) {
|
|
5497
5529
|
return roles.find((r) => r.name === name);
|
|
@@ -5635,7 +5667,7 @@ function roleScopedProvider(base, role, blocked) {
|
|
|
5635
5667
|
return allow ? allow.has(name) : true;
|
|
5636
5668
|
};
|
|
5637
5669
|
return {
|
|
5638
|
-
list: () => base.list().filter((
|
|
5670
|
+
list: () => base.list().filter((t81) => permitted(t81.name)),
|
|
5639
5671
|
get: (name) => permitted(name) ? base.get(name) : void 0
|
|
5640
5672
|
};
|
|
5641
5673
|
}
|
|
@@ -5662,7 +5694,7 @@ function createRoleScope(base, sessionRole, blocked) {
|
|
|
5662
5694
|
}
|
|
5663
5695
|
function unknownRoleTools(base, role, blocked) {
|
|
5664
5696
|
if (!role?.tools) return [];
|
|
5665
|
-
const available2 = new Set(base.list().map((
|
|
5697
|
+
const available2 = new Set(base.list().map((t81) => t81.name));
|
|
5666
5698
|
const blockedSet = new Set(blocked);
|
|
5667
5699
|
return role.tools.filter((name) => !available2.has(name) && !blockedSet.has(name));
|
|
5668
5700
|
}
|
|
@@ -5998,7 +6030,7 @@ function createToolScope(base) {
|
|
|
5998
6030
|
const permitted = (name) => allow ? allow.has(name) : true;
|
|
5999
6031
|
return {
|
|
6000
6032
|
provider: {
|
|
6001
|
-
list: () => base.list().filter((
|
|
6033
|
+
list: () => base.list().filter((t81) => permitted(t81.name)),
|
|
6002
6034
|
get: (name) => permitted(name) ? base.get(name) : void 0
|
|
6003
6035
|
},
|
|
6004
6036
|
enter: (next) => {
|
|
@@ -6168,7 +6200,7 @@ function scanHooks(dir, issues) {
|
|
|
6168
6200
|
return [...parsed.entries].map(([type, list]) => ({
|
|
6169
6201
|
type,
|
|
6170
6202
|
count: list.reduce((sum, entry) => sum + entry.hooks.length, 0)
|
|
6171
|
-
})).filter((
|
|
6203
|
+
})).filter((t81) => t81.count > 0).sort((a, b) => a.type.localeCompare(b.type));
|
|
6172
6204
|
}
|
|
6173
6205
|
function scanMcp(dir, plugin, issues) {
|
|
6174
6206
|
const path = join(dir, PLUGIN_LAYOUT.mcp);
|
|
@@ -6264,6 +6296,7 @@ var ManifestSchema = z.object({
|
|
|
6264
6296
|
epochVersion: z.string().min(1).optional(),
|
|
6265
6297
|
homepage: z.string().min(1).optional(),
|
|
6266
6298
|
keywords: z.array(z.string().min(1)).optional(),
|
|
6299
|
+
dependencies: z.array(z.string().min(1)).optional().catch(void 0),
|
|
6267
6300
|
displayName: z.string().min(1).optional(),
|
|
6268
6301
|
category: z.string().min(1).optional(),
|
|
6269
6302
|
icon: z.string().min(1).optional(),
|
|
@@ -6306,6 +6339,23 @@ function readPluginManifest(dir) {
|
|
|
6306
6339
|
})
|
|
6307
6340
|
});
|
|
6308
6341
|
}
|
|
6342
|
+
const rawDependencies = parsed?.dependencies;
|
|
6343
|
+
if (rawDependencies !== void 0 && !Array.isArray(rawDependencies)) {
|
|
6344
|
+
issues.push({
|
|
6345
|
+
path: `${path}.dependencies`,
|
|
6346
|
+
message: t("plugin_manifest.bad_dependencies", { raw: JSON.stringify(rawDependencies) })
|
|
6347
|
+
});
|
|
6348
|
+
}
|
|
6349
|
+
if (Array.isArray(rawDependencies)) {
|
|
6350
|
+
for (const item of rawDependencies) {
|
|
6351
|
+
if (typeof item !== "string" || !isValidPluginName(item)) {
|
|
6352
|
+
issues.push({
|
|
6353
|
+
path: `${path}.dependencies`,
|
|
6354
|
+
message: t("plugin_manifest.bad_dependency_name", { name: String(item) })
|
|
6355
|
+
});
|
|
6356
|
+
}
|
|
6357
|
+
}
|
|
6358
|
+
}
|
|
6309
6359
|
const checked = parseLenient(ManifestSchema.optional(), parsed, void 0);
|
|
6310
6360
|
if (!checked.value) {
|
|
6311
6361
|
issues.push(
|
|
@@ -6607,6 +6657,7 @@ function loadPlugins(opts) {
|
|
|
6607
6657
|
const state = readPluginRecords(statePath);
|
|
6608
6658
|
const out = noPlugins();
|
|
6609
6659
|
out.issues.push(...state.issues);
|
|
6660
|
+
const declared = /* @__PURE__ */ new Map();
|
|
6610
6661
|
const epochVersion = opts.epochVersion ?? currentEpochVersion();
|
|
6611
6662
|
for (const record of state.records) {
|
|
6612
6663
|
const outcome = admit(record, epochVersion);
|
|
@@ -6625,6 +6676,21 @@ function loadPlugins(opts) {
|
|
|
6625
6676
|
continue;
|
|
6626
6677
|
}
|
|
6627
6678
|
collect(record, out);
|
|
6679
|
+
if (outcome.manifest?.dependencies?.length) {
|
|
6680
|
+
declared.set(record.name, outcome.manifest.dependencies);
|
|
6681
|
+
}
|
|
6682
|
+
}
|
|
6683
|
+
const present = new Set(out.loaded.map((plugin) => plugin.name));
|
|
6684
|
+
for (const [name, dependencies] of declared) {
|
|
6685
|
+
if (!present.has(name)) continue;
|
|
6686
|
+
for (const dependency of dependencies) {
|
|
6687
|
+
if (present.has(dependency)) continue;
|
|
6688
|
+
diags?.warn(
|
|
6689
|
+
MODULE,
|
|
6690
|
+
t("plugin_load.dependency_missing", { name, dependency }),
|
|
6691
|
+
"plugin-dependency-missing"
|
|
6692
|
+
);
|
|
6693
|
+
}
|
|
6628
6694
|
}
|
|
6629
6695
|
for (const detail of issueDetails(out.issues)) {
|
|
6630
6696
|
diags?.warn(MODULE, detail, "plugin-invalid");
|
|
@@ -6651,7 +6717,7 @@ function admit(record, epochVersion) {
|
|
|
6651
6717
|
if (!version.ok) {
|
|
6652
6718
|
return { reason: version.reason, code: "plugin-version-mismatch" };
|
|
6653
6719
|
}
|
|
6654
|
-
return {};
|
|
6720
|
+
return { manifest: manifest.manifest };
|
|
6655
6721
|
}
|
|
6656
6722
|
function collect(record, out) {
|
|
6657
6723
|
const { name, path: dir } = record;
|
|
@@ -6997,99 +7063,426 @@ function firstLine3(err) {
|
|
|
6997
7063
|
const message = err instanceof Error ? err.message : String(err);
|
|
6998
7064
|
return message.split("\n")[0] ?? message;
|
|
6999
7065
|
}
|
|
7000
|
-
var
|
|
7001
|
-
var
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7066
|
+
var MARKETPLACE_FILE = "epoch-marketplace.json";
|
|
7067
|
+
var NAME_PATTERN = PLUGIN_NAME_PATTERN;
|
|
7068
|
+
var EntryCategoryInput = z.union([z.string().min(1), z.array(z.string().min(1))]).optional().catch(void 0);
|
|
7069
|
+
var EntryShape = z.object({
|
|
7070
|
+
name: z.string().regex(NAME_PATTERN),
|
|
7071
|
+
description: z.string().min(1).optional(),
|
|
7072
|
+
source: z.string().min(1),
|
|
7073
|
+
category: EntryCategoryInput,
|
|
7074
|
+
keywords: z.array(z.string().min(1)).optional(),
|
|
7075
|
+
author: PluginAuthorSchema.optional(),
|
|
7076
|
+
downloads: z.number().int().nonnegative().optional(),
|
|
7077
|
+
likes: z.number().int().nonnegative().optional(),
|
|
7078
|
+
displayName: z.string().min(1).optional(),
|
|
7079
|
+
icon: z.string().min(1).optional(),
|
|
7080
|
+
version: z.string().min(1).optional(),
|
|
7081
|
+
changelog: z.string().min(1).optional(),
|
|
7082
|
+
size: z.number().int().positive().optional(),
|
|
7083
|
+
homepage: z.string().min(1).optional(),
|
|
7084
|
+
visibility: z.enum(PLUGIN_VISIBILITY).optional().catch(void 0),
|
|
7085
|
+
status: z.enum(["listed", "reviewing", "rejected", "offline"]).optional().catch(void 0)
|
|
7086
|
+
});
|
|
7087
|
+
var EntrySchema = EntryShape.transform(({ category, ...rest }) => {
|
|
7088
|
+
const picked = category === void 0 ? [] : typeof category === "string" ? [category] : category;
|
|
7089
|
+
return { ...rest, ...picked.length === 0 ? {} : { category: [...picked] } };
|
|
7090
|
+
});
|
|
7091
|
+
var MARKETPLACE_DISPLAY_FIELDS = [
|
|
7092
|
+
"status",
|
|
7093
|
+
"downloads",
|
|
7094
|
+
"likes",
|
|
7095
|
+
"author",
|
|
7096
|
+
"category",
|
|
7097
|
+
"visibility",
|
|
7098
|
+
"icon",
|
|
7099
|
+
"homepage",
|
|
7100
|
+
"size"
|
|
7101
|
+
];
|
|
7102
|
+
var DisplaySchema = z.object({
|
|
7103
|
+
fields: z.array(z.string().min(1)).optional()
|
|
7104
|
+
});
|
|
7105
|
+
var CategoryNodeSchema = z.lazy(
|
|
7106
|
+
() => z.object({
|
|
7107
|
+
id: z.string().min(1),
|
|
7108
|
+
label: z.string().min(1).optional(),
|
|
7109
|
+
children: z.array(CategoryNodeSchema).optional()
|
|
7110
|
+
})
|
|
7111
|
+
);
|
|
7112
|
+
var CategoriesSchema = z.array(CategoryNodeSchema).refine(hasUniqueCategoryIds, { message: "category ids must be unique across the whole tree" }).optional().catch(void 0);
|
|
7113
|
+
function hasUniqueCategoryIds(nodes) {
|
|
7114
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7115
|
+
const walk3 = (list) => list.every((node) => {
|
|
7116
|
+
if (seen.has(node.id)) return false;
|
|
7117
|
+
seen.add(node.id);
|
|
7118
|
+
return node.children === void 0 || walk3(node.children);
|
|
7119
|
+
});
|
|
7120
|
+
return walk3(nodes);
|
|
7121
|
+
}
|
|
7122
|
+
var CatalogSchema = z.object({
|
|
7123
|
+
name: z.string().regex(NAME_PATTERN),
|
|
7124
|
+
description: z.string().min(1).optional(),
|
|
7125
|
+
owner: z.object({ name: z.string().min(1), url: z.string().min(1).optional() }).optional(),
|
|
7126
|
+
display: DisplaySchema.optional(),
|
|
7127
|
+
categories: CategoriesSchema,
|
|
7128
|
+
plugins: z.array(EntrySchema)
|
|
7129
|
+
});
|
|
7130
|
+
var RecordSchema2 = z.object({
|
|
7131
|
+
name: z.string().regex(NAME_PATTERN),
|
|
7132
|
+
source: z.string().min(1),
|
|
7133
|
+
addedAt: z.number(),
|
|
7134
|
+
catalog: CatalogSchema
|
|
7135
|
+
});
|
|
7136
|
+
var StateSchema2 = z.object({
|
|
7137
|
+
version: z.literal(1).optional(),
|
|
7138
|
+
marketplaces: z.array(RecordSchema2)
|
|
7139
|
+
});
|
|
7140
|
+
function projectEntryForDisplay(entry, display) {
|
|
7141
|
+
const allowed = display?.fields;
|
|
7142
|
+
if (allowed === void 0) return entry;
|
|
7143
|
+
const out = { ...entry };
|
|
7144
|
+
for (const field of MARKETPLACE_DISPLAY_FIELDS) {
|
|
7145
|
+
if (!displayAllows(display, field)) delete out[field];
|
|
7146
|
+
}
|
|
7147
|
+
return out;
|
|
7148
|
+
}
|
|
7149
|
+
function displayAllows(display, field) {
|
|
7150
|
+
const allowed = display?.fields;
|
|
7151
|
+
if (allowed === void 0) return true;
|
|
7152
|
+
return allowed.includes(field);
|
|
7153
|
+
}
|
|
7154
|
+
function readMarketplaces(statePath) {
|
|
7155
|
+
if (!existsSync(statePath)) return { records: [], issues: [] };
|
|
7156
|
+
let raw;
|
|
7157
|
+
try {
|
|
7158
|
+
raw = JSON.parse(readFileSync(statePath, "utf-8"));
|
|
7159
|
+
} catch (err) {
|
|
7010
7160
|
return {
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7161
|
+
records: [],
|
|
7162
|
+
issues: [
|
|
7163
|
+
{ path: statePath, message: t("plugin_marketplace.bad_json", { reason: first(err) }) }
|
|
7164
|
+
]
|
|
7015
7165
|
};
|
|
7016
7166
|
}
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
if (!NPM_SPEC.test(pkg)) return void 0;
|
|
7027
|
-
return { type: "npm", raw: input, target: pkg };
|
|
7028
|
-
}
|
|
7029
|
-
if (input.startsWith("host:")) {
|
|
7030
|
-
const opaque = input.slice("host:".length).trim();
|
|
7031
|
-
if (!opaque) return void 0;
|
|
7032
|
-
return { type: "host", raw: input, target: opaque };
|
|
7033
|
-
}
|
|
7034
|
-
if (input.startsWith("https://") || input.startsWith("http://")) {
|
|
7035
|
-
const [url = "", fragment] = input.split("#", 2);
|
|
7036
|
-
if (!REMOTE_URL.test(url)) return void 0;
|
|
7037
|
-
const sha = fragment?.startsWith("sha256=") ? fragment.slice("sha256=".length) : void 0;
|
|
7038
|
-
if (isArchiveUrl(url)) {
|
|
7039
|
-
if (sha !== void 0 && !/^[a-f0-9]{64}$/i.test(sha)) return void 0;
|
|
7040
|
-
return {
|
|
7041
|
-
type: "archive",
|
|
7042
|
-
raw: input,
|
|
7043
|
-
target: url,
|
|
7044
|
-
...sha ? { sha256: sha.toLowerCase() } : {}
|
|
7045
|
-
};
|
|
7046
|
-
}
|
|
7047
|
-
return { type: "git", raw: input, target: url };
|
|
7048
|
-
}
|
|
7049
|
-
const abs = isAbsolute(input) ? input : resolve(input);
|
|
7050
|
-
if (isArchiveUrl(abs)) {
|
|
7051
|
-
return { type: "archive", raw: input, target: abs, localFile: true };
|
|
7167
|
+
const checked = parseLenient(StateSchema2.optional(), raw, void 0);
|
|
7168
|
+
if (!checked.value) {
|
|
7169
|
+
return {
|
|
7170
|
+
records: [],
|
|
7171
|
+
issues: checked.issues.map((i) => ({
|
|
7172
|
+
path: statePath,
|
|
7173
|
+
message: t("plugin_marketplace.issue", { path: i.path, message: i.message })
|
|
7174
|
+
}))
|
|
7175
|
+
};
|
|
7052
7176
|
}
|
|
7053
|
-
return {
|
|
7177
|
+
return { records: checked.value.marketplaces, issues: [] };
|
|
7054
7178
|
}
|
|
7055
|
-
function
|
|
7056
|
-
|
|
7179
|
+
async function mutate(statePath, fn) {
|
|
7180
|
+
const release = await acquireStateLock(statePath);
|
|
7181
|
+
try {
|
|
7182
|
+
const next = fn(readMarketplaces(statePath).records);
|
|
7183
|
+
if (!next) return false;
|
|
7184
|
+
writeStateFile(statePath, JSON.stringify({ version: 1, marketplaces: next }, null, 2));
|
|
7185
|
+
return true;
|
|
7186
|
+
} finally {
|
|
7187
|
+
release();
|
|
7188
|
+
}
|
|
7057
7189
|
}
|
|
7058
|
-
function
|
|
7059
|
-
|
|
7060
|
-
if (!
|
|
7061
|
-
const
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7190
|
+
async function addMarketplace(source, opts) {
|
|
7191
|
+
const fetched = await fetchCatalog(source);
|
|
7192
|
+
if (!fetched.ok) return fetched;
|
|
7193
|
+
const record = {
|
|
7194
|
+
name: fetched.catalog.name,
|
|
7195
|
+
source: source.trim(),
|
|
7196
|
+
addedAt: Date.now(),
|
|
7197
|
+
catalog: fetched.catalog
|
|
7198
|
+
};
|
|
7199
|
+
const written = await mutate(
|
|
7200
|
+
opts.statePath,
|
|
7201
|
+
(records) => records.some((r) => r.name === record.name) ? void 0 : [...records, record].sort((a, b) => a.name.localeCompare(b.name))
|
|
7202
|
+
);
|
|
7203
|
+
return written ? { ok: true, record } : {
|
|
7204
|
+
ok: false,
|
|
7205
|
+
reason: t("plugin_marketplace.already_added", { name: record.name })
|
|
7206
|
+
};
|
|
7065
7207
|
}
|
|
7066
|
-
function
|
|
7067
|
-
|
|
7208
|
+
async function removeMarketplace(name, opts) {
|
|
7209
|
+
const written = await mutate(
|
|
7210
|
+
opts.statePath,
|
|
7211
|
+
(records) => records.some((r) => r.name === name) ? records.filter((r) => r.name !== name) : void 0
|
|
7212
|
+
);
|
|
7213
|
+
return written ? { ok: true } : { ok: false, reason: t("plugin_marketplace.not_added", { name }) };
|
|
7068
7214
|
}
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7215
|
+
async function updateMarketplace(name, opts) {
|
|
7216
|
+
const existing = readMarketplaces(opts.statePath).records.find((r) => r.name === name);
|
|
7217
|
+
if (!existing) return { ok: false, reason: t("plugin_marketplace.not_added", { name }) };
|
|
7218
|
+
const fetched = await fetchCatalog(existing.source);
|
|
7219
|
+
if (!fetched.ok) return fetched;
|
|
7220
|
+
if (fetched.catalog.name !== name) {
|
|
7073
7221
|
return {
|
|
7074
7222
|
ok: false,
|
|
7075
|
-
reason: t("
|
|
7223
|
+
reason: t("plugin_marketplace.renamed", {
|
|
7224
|
+
source: existing.source,
|
|
7225
|
+
name: fetched.catalog.name
|
|
7226
|
+
})
|
|
7076
7227
|
};
|
|
7077
7228
|
}
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
return await runInstall(resolved, staging, opts);
|
|
7082
|
-
} finally {
|
|
7083
|
-
rmSync(staging, { recursive: true, force: true });
|
|
7084
|
-
}
|
|
7229
|
+
const record = { ...existing, catalog: fetched.catalog };
|
|
7230
|
+
await mutate(opts.statePath, (records) => records.map((r) => r.name === name ? record : r));
|
|
7231
|
+
return { ok: true, record };
|
|
7085
7232
|
}
|
|
7086
|
-
|
|
7087
|
-
const
|
|
7088
|
-
|
|
7089
|
-
const
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7233
|
+
function searchMarketplaces(keyword, statePath) {
|
|
7234
|
+
const needle = keyword.trim().toLowerCase();
|
|
7235
|
+
const hits = [];
|
|
7236
|
+
for (const record of readMarketplaces(statePath).records) {
|
|
7237
|
+
for (const entry of record.catalog.plugins) {
|
|
7238
|
+
const haystack = [
|
|
7239
|
+
entry.name,
|
|
7240
|
+
entry.description ?? "",
|
|
7241
|
+
...entry.category ?? [],
|
|
7242
|
+
entry.author?.name ?? "",
|
|
7243
|
+
...entry.keywords ?? []
|
|
7244
|
+
].join(" ").toLowerCase();
|
|
7245
|
+
if (needle && !haystack.includes(needle)) continue;
|
|
7246
|
+
hits.push({
|
|
7247
|
+
marketplace: record.name,
|
|
7248
|
+
entry: projectEntryForDisplay(entry, record.catalog.display),
|
|
7249
|
+
ref: `${record.name}/${entry.name}`
|
|
7250
|
+
});
|
|
7251
|
+
}
|
|
7252
|
+
}
|
|
7253
|
+
return hits;
|
|
7254
|
+
}
|
|
7255
|
+
function resolveMarketplaceRef(input, statePath) {
|
|
7256
|
+
const parts = input.trim().split("/");
|
|
7257
|
+
if (parts.length !== 2) return void 0;
|
|
7258
|
+
const [market = "", plugin = ""] = parts;
|
|
7259
|
+
if (!NAME_PATTERN.test(market) || !NAME_PATTERN.test(plugin)) return void 0;
|
|
7260
|
+
const record = readMarketplaces(statePath).records.find((r) => r.name === market);
|
|
7261
|
+
if (!record) {
|
|
7262
|
+
return {
|
|
7263
|
+
ok: false,
|
|
7264
|
+
reason: t("plugin_marketplace.market_not_added", { market, input })
|
|
7265
|
+
};
|
|
7266
|
+
}
|
|
7267
|
+
const entry = record.catalog.plugins.find((p) => p.name === plugin);
|
|
7268
|
+
if (!entry) {
|
|
7269
|
+
return {
|
|
7270
|
+
ok: false,
|
|
7271
|
+
reason: t("plugin_marketplace.plugin_not_in_market", { market, plugin })
|
|
7272
|
+
};
|
|
7273
|
+
}
|
|
7274
|
+
const source = resolveEntrySource(entry.source, record.source);
|
|
7275
|
+
if (!source) {
|
|
7276
|
+
return {
|
|
7277
|
+
ok: false,
|
|
7278
|
+
reason: t("plugin_marketplace.entry_unresolvable", {
|
|
7279
|
+
market,
|
|
7280
|
+
plugin,
|
|
7281
|
+
source: entry.source
|
|
7282
|
+
})
|
|
7283
|
+
};
|
|
7284
|
+
}
|
|
7285
|
+
return { ok: true, ref: { marketplace: market, source } };
|
|
7286
|
+
}
|
|
7287
|
+
function resolveEntrySource(entry, marketSource) {
|
|
7288
|
+
const spec = entry.trim();
|
|
7289
|
+
if (!spec.startsWith(".") && !spec.startsWith("/")) return spec;
|
|
7290
|
+
const rel = spec.replace(/^\.\//, "").replace(/^\//, "");
|
|
7291
|
+
if (rel === "" || rel.split("/").includes("..")) return void 0;
|
|
7292
|
+
const market = marketSource.trim();
|
|
7293
|
+
if (market.startsWith("github:") || market.startsWith("git+")) {
|
|
7294
|
+
const [base = "", fragment] = market.split("#", 2);
|
|
7295
|
+
const prefix = fragment?.startsWith("subdir=") ? `${fragment.slice("subdir=".length)}/` : "";
|
|
7296
|
+
return `${base}#subdir=${prefix}${rel}`;
|
|
7297
|
+
}
|
|
7298
|
+
if (market.startsWith("https://") || market.startsWith("http://")) {
|
|
7299
|
+
return `${market.replace(/\/[^/]*$/, "")}/${rel}`;
|
|
7300
|
+
}
|
|
7301
|
+
return join(marketDir(market), rel);
|
|
7302
|
+
}
|
|
7303
|
+
function findMarketplaceEntryByName(name, statePath) {
|
|
7304
|
+
for (const record of readMarketplaces(statePath).records) {
|
|
7305
|
+
const entry = record.catalog.plugins.find((plugin) => plugin.name === name);
|
|
7306
|
+
if (!entry) continue;
|
|
7307
|
+
const source = resolveEntrySource(entry.source, record.source);
|
|
7308
|
+
if (!source) continue;
|
|
7309
|
+
return { marketplace: record.name, source };
|
|
7310
|
+
}
|
|
7311
|
+
return void 0;
|
|
7312
|
+
}
|
|
7313
|
+
async function fetchCatalog(source) {
|
|
7314
|
+
const input = source.trim();
|
|
7315
|
+
if (!input) return { ok: false, reason: t("plugin_marketplace.source_empty") };
|
|
7316
|
+
const local = localCatalogPath(input);
|
|
7317
|
+
if (local) {
|
|
7318
|
+
if (!existsSync(local)) {
|
|
7319
|
+
return { ok: false, reason: t("plugin_marketplace.local_missing", { path: local }) };
|
|
7320
|
+
}
|
|
7321
|
+
try {
|
|
7322
|
+
return parseCatalog(readFileSync(local, "utf-8"), local);
|
|
7323
|
+
} catch (err) {
|
|
7324
|
+
return { ok: false, reason: t("plugin_marketplace.read_failed", { reason: first(err) }) };
|
|
7325
|
+
}
|
|
7326
|
+
}
|
|
7327
|
+
const url = catalogUrl(input);
|
|
7328
|
+
if (!url) {
|
|
7329
|
+
return {
|
|
7330
|
+
ok: false,
|
|
7331
|
+
reason: t("plugin_marketplace.bad_url", { input, file: MARKETPLACE_FILE })
|
|
7332
|
+
};
|
|
7333
|
+
}
|
|
7334
|
+
try {
|
|
7335
|
+
const response = await fetch(url, { redirect: "follow" });
|
|
7336
|
+
if (!response.ok) {
|
|
7337
|
+
const vars = { url, status: response.status };
|
|
7338
|
+
return {
|
|
7339
|
+
ok: false,
|
|
7340
|
+
reason: looksPrivate(response.status) ? t("marketplace.fetch_failed_private", vars) : t("marketplace.fetch_failed", vars)
|
|
7341
|
+
};
|
|
7342
|
+
}
|
|
7343
|
+
return parseCatalog(await response.text(), url);
|
|
7344
|
+
} catch (err) {
|
|
7345
|
+
return { ok: false, reason: t("marketplace.fetch_error", { url, reason: first(err) }) };
|
|
7346
|
+
}
|
|
7347
|
+
}
|
|
7348
|
+
function looksPrivate(status) {
|
|
7349
|
+
return status === 401 || status === 403 || status === 404;
|
|
7350
|
+
}
|
|
7351
|
+
function catalogUrl(input) {
|
|
7352
|
+
if (input.startsWith("github:")) {
|
|
7353
|
+
const slug = input.slice("github:".length);
|
|
7354
|
+
if (!/^[\w.-]+\/[\w.-]+$/.test(slug)) return void 0;
|
|
7355
|
+
return `https://raw.githubusercontent.com/${slug}/HEAD/${MARKETPLACE_FILE}`;
|
|
7356
|
+
}
|
|
7357
|
+
if (!input.startsWith("https://") && !input.startsWith("http://")) return void 0;
|
|
7358
|
+
return input.endsWith(".json") ? input : `${input.replace(/\/+$/, "")}/${MARKETPLACE_FILE}`;
|
|
7359
|
+
}
|
|
7360
|
+
function localCatalogPath(input) {
|
|
7361
|
+
if (/^[a-z][a-z0-9+.-]+:/i.test(input) || input.startsWith("//")) return void 0;
|
|
7362
|
+
const abs = isAbsolute(input) ? input : resolve(input);
|
|
7363
|
+
if (existsSync(abs) && statSync(abs).isDirectory()) return join(abs, MARKETPLACE_FILE);
|
|
7364
|
+
return abs;
|
|
7365
|
+
}
|
|
7366
|
+
function marketDir(market) {
|
|
7367
|
+
const abs = isAbsolute(market) ? market : resolve(market);
|
|
7368
|
+
if (existsSync(abs) && statSync(abs).isDirectory()) return abs;
|
|
7369
|
+
return abs.replace(/[/\\][^/\\]*$/, "");
|
|
7370
|
+
}
|
|
7371
|
+
function parseCatalog(body2, where) {
|
|
7372
|
+
let raw;
|
|
7373
|
+
try {
|
|
7374
|
+
raw = JSON.parse(body2);
|
|
7375
|
+
} catch (err) {
|
|
7376
|
+
return {
|
|
7377
|
+
ok: false,
|
|
7378
|
+
reason: t("plugin_marketplace.catalog_bad_json", { where, reason: first(err) })
|
|
7379
|
+
};
|
|
7380
|
+
}
|
|
7381
|
+
const checked = parseLenient(CatalogSchema.optional(), raw, void 0);
|
|
7382
|
+
if (!checked.value) {
|
|
7383
|
+
const detail = checked.issues.map((i) => t("plugin_marketplace.issue", { path: i.path, message: i.message })).join(t("plugin_marketplace.catalog_issue_sep"));
|
|
7384
|
+
return { ok: false, reason: t("plugin_marketplace.catalog_invalid", { where, detail }) };
|
|
7385
|
+
}
|
|
7386
|
+
return { ok: true, catalog: checked.value };
|
|
7387
|
+
}
|
|
7388
|
+
function first(err) {
|
|
7389
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7390
|
+
return message.split("\n")[0] ?? t("plugin_marketplace.unknown_error");
|
|
7391
|
+
}
|
|
7392
|
+
var NPM_SPEC = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*(?:@[a-zA-Z0-9.^~*+-]+)?$/;
|
|
7393
|
+
var REMOTE_URL = /^https?:\/\/[^\s'"\\^|<>]+$/;
|
|
7394
|
+
function resolveSource(raw) {
|
|
7395
|
+
const input = raw.trim();
|
|
7396
|
+
if (!input) return void 0;
|
|
7397
|
+
if (input.startsWith("github:")) {
|
|
7398
|
+
const [slug = "", fragment] = input.slice("github:".length).split("#", 2);
|
|
7399
|
+
if (!/^[\w.-]+\/[\w.-]+$/.test(slug)) return void 0;
|
|
7400
|
+
const sub = subdirOf(fragment);
|
|
7401
|
+
if (!sub.ok) return void 0;
|
|
7402
|
+
return {
|
|
7403
|
+
type: "git",
|
|
7404
|
+
raw: input,
|
|
7405
|
+
target: `https://github.com/${slug}.git`,
|
|
7406
|
+
...sub.subdir ? { subdir: sub.subdir } : {}
|
|
7407
|
+
};
|
|
7408
|
+
}
|
|
7409
|
+
if (input.startsWith("git+")) {
|
|
7410
|
+
const [url = "", fragment] = input.slice("git+".length).split("#", 2);
|
|
7411
|
+
if (!REMOTE_URL.test(url)) return void 0;
|
|
7412
|
+
const sub = subdirOf(fragment);
|
|
7413
|
+
if (!sub.ok) return void 0;
|
|
7414
|
+
return { type: "git", raw: input, target: url, ...sub.subdir ? { subdir: sub.subdir } : {} };
|
|
7415
|
+
}
|
|
7416
|
+
if (input.startsWith("npm:")) {
|
|
7417
|
+
const pkg = input.slice("npm:".length);
|
|
7418
|
+
if (!NPM_SPEC.test(pkg)) return void 0;
|
|
7419
|
+
return { type: "npm", raw: input, target: pkg };
|
|
7420
|
+
}
|
|
7421
|
+
if (input.startsWith("host:")) {
|
|
7422
|
+
const opaque = input.slice("host:".length).trim();
|
|
7423
|
+
if (!opaque) return void 0;
|
|
7424
|
+
return { type: "host", raw: input, target: opaque };
|
|
7425
|
+
}
|
|
7426
|
+
if (input.startsWith("https://") || input.startsWith("http://")) {
|
|
7427
|
+
const [url = "", fragment] = input.split("#", 2);
|
|
7428
|
+
if (!REMOTE_URL.test(url)) return void 0;
|
|
7429
|
+
const sha = fragment?.startsWith("sha256=") ? fragment.slice("sha256=".length) : void 0;
|
|
7430
|
+
if (isArchiveUrl(url)) {
|
|
7431
|
+
if (sha !== void 0 && !/^[a-f0-9]{64}$/i.test(sha)) return void 0;
|
|
7432
|
+
return {
|
|
7433
|
+
type: "archive",
|
|
7434
|
+
raw: input,
|
|
7435
|
+
target: url,
|
|
7436
|
+
...sha ? { sha256: sha.toLowerCase() } : {}
|
|
7437
|
+
};
|
|
7438
|
+
}
|
|
7439
|
+
return { type: "git", raw: input, target: url };
|
|
7440
|
+
}
|
|
7441
|
+
const abs = isAbsolute(input) ? input : resolve(input);
|
|
7442
|
+
if (isArchiveUrl(abs)) {
|
|
7443
|
+
return { type: "archive", raw: input, target: abs, localFile: true };
|
|
7444
|
+
}
|
|
7445
|
+
return { type: "local", raw: input, target: abs };
|
|
7446
|
+
}
|
|
7447
|
+
function isArchiveUrl(url) {
|
|
7448
|
+
return isWirePluginArchiveName(url);
|
|
7449
|
+
}
|
|
7450
|
+
function subdirOf(fragment) {
|
|
7451
|
+
if (fragment === void 0 || fragment === "") return { ok: true };
|
|
7452
|
+
if (!fragment.startsWith("subdir=")) return { ok: false };
|
|
7453
|
+
const rel = fragment.slice("subdir=".length).replace(/\/+$/, "");
|
|
7454
|
+
if (!/^[\w.-]+(?:\/[\w.-]+)*$/.test(rel)) return { ok: false };
|
|
7455
|
+
if (rel.split("/").includes("..")) return { ok: false };
|
|
7456
|
+
return { ok: true, subdir: rel };
|
|
7457
|
+
}
|
|
7458
|
+
function pluginRoot(source, staging) {
|
|
7459
|
+
return source.subdir ? join(staging, source.subdir) : staging;
|
|
7460
|
+
}
|
|
7461
|
+
// src/plugin/install.ts
|
|
7462
|
+
async function installPlugin(source, opts) {
|
|
7463
|
+
const resolved = resolveSource(source);
|
|
7464
|
+
if (!resolved) {
|
|
7465
|
+
return {
|
|
7466
|
+
ok: false,
|
|
7467
|
+
reason: t("plugin_install.bad_source", { source })
|
|
7468
|
+
};
|
|
7469
|
+
}
|
|
7470
|
+
mkdirSync(opts.pluginsDir, { recursive: true });
|
|
7471
|
+
const staging = join(opts.pluginsDir, `.staging-${randomUUID().slice(0, 8)}`);
|
|
7472
|
+
try {
|
|
7473
|
+
return await runInstall(resolved, staging, opts);
|
|
7474
|
+
} finally {
|
|
7475
|
+
rmSync(staging, { recursive: true, force: true });
|
|
7476
|
+
}
|
|
7477
|
+
}
|
|
7478
|
+
async function runInstall(resolved, staging, opts) {
|
|
7479
|
+
const rootStaging = join(staging, "root");
|
|
7480
|
+
const fetched = await fetchInto(resolved, rootStaging, opts);
|
|
7481
|
+
if (!fetched.ok) return { ok: false, reason: fetched.reason };
|
|
7482
|
+
const readDir = resolved.type === "local" ? resolved.target : pluginRoot(resolved, rootStaging);
|
|
7483
|
+
const read = readPluginManifest(readDir);
|
|
7484
|
+
const manifest = read.manifest;
|
|
7485
|
+
if (!manifest) {
|
|
7093
7486
|
const detail = read.issues.map((i) => t("plugin_install.issue_line", { path: i.path, message: i.message })).join("\n");
|
|
7094
7487
|
return { ok: false, reason: t("plugin_install.manifest_unusable", { detail: `
|
|
7095
7488
|
${detail}` }) };
|
|
@@ -7099,12 +7492,20 @@ ${detail}` }) };
|
|
|
7099
7492
|
const current = opts.epochVersion ?? currentEpochVersion();
|
|
7100
7493
|
const version = checkEpochVersion(manifest.epochVersion, current);
|
|
7101
7494
|
const versionUnmet = !version.ok && manifest.epochVersion ? { required: manifest.epochVersion, current, reason: version.reason } : void 0;
|
|
7495
|
+
const closure = await resolveClosure({
|
|
7496
|
+
root: manifest.name,
|
|
7497
|
+
declared: manifest.dependencies ?? [],
|
|
7498
|
+
installed: new Set(new PluginStore(opts.statePath).read().records.map((r) => r.name)),
|
|
7499
|
+
staging,
|
|
7500
|
+
opts
|
|
7501
|
+
});
|
|
7102
7502
|
const preview3 = {
|
|
7103
7503
|
manifest,
|
|
7104
7504
|
source: resolved,
|
|
7105
7505
|
inventory: scanPluginDir(readDir, manifest.name),
|
|
7106
7506
|
...conflict ? { conflict } : {},
|
|
7107
|
-
...versionUnmet ? { versionUnmet } : {}
|
|
7507
|
+
...versionUnmet ? { versionUnmet } : {},
|
|
7508
|
+
...closure.report.length > 0 ? { dependencies: closure.report } : {}
|
|
7108
7509
|
};
|
|
7109
7510
|
if (opts.replace !== void 0 && manifest.name !== opts.replace) {
|
|
7110
7511
|
return {
|
|
@@ -7127,52 +7528,199 @@ ${detail}` }) };
|
|
|
7127
7528
|
if (opts.confirm && !await opts.confirm(preview3)) {
|
|
7128
7529
|
return { ok: false, reason: t("plugin.install_cancelled"), cancelled: true, preview: preview3 };
|
|
7129
7530
|
}
|
|
7130
|
-
const
|
|
7531
|
+
const records = await commitAll(
|
|
7532
|
+
[
|
|
7533
|
+
{
|
|
7534
|
+
name: manifest.name,
|
|
7535
|
+
version: manifest.version,
|
|
7536
|
+
source: resolved,
|
|
7537
|
+
stagingDir: rootStaging,
|
|
7538
|
+
...opts.marketplace ? { marketplace: opts.marketplace } : {}
|
|
7539
|
+
},
|
|
7540
|
+
...closure.plans.map((plan) => ({
|
|
7541
|
+
name: plan.name,
|
|
7542
|
+
version: plan.manifest.version,
|
|
7543
|
+
source: plan.source,
|
|
7544
|
+
stagingDir: plan.stagingDir,
|
|
7545
|
+
...plan.marketplace ? { marketplace: plan.marketplace } : {}
|
|
7546
|
+
}))
|
|
7547
|
+
],
|
|
7548
|
+
opts
|
|
7549
|
+
);
|
|
7550
|
+
const record = records?.find((r) => r.name === manifest.name);
|
|
7131
7551
|
return record ? { ok: true, record, preview: preview3 } : {
|
|
7132
7552
|
ok: false,
|
|
7133
7553
|
preview: preview3,
|
|
7134
7554
|
reason: t("plugin_install.raced", { name: manifest.name })
|
|
7135
7555
|
};
|
|
7136
7556
|
}
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
const
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
name,
|
|
7157
|
-
version:
|
|
7158
|
-
source: source.raw,
|
|
7159
|
-
sourceType: source.type,
|
|
7557
|
+
var DEPENDENCY_LIMIT = 32;
|
|
7558
|
+
async function commitAll(entries2, opts) {
|
|
7559
|
+
const records = [];
|
|
7560
|
+
for (const entry of entries2) {
|
|
7561
|
+
const dest = join(opts.pluginsDir, entry.name);
|
|
7562
|
+
removeInstallDest(dest);
|
|
7563
|
+
let linked = entry.source.type === "local";
|
|
7564
|
+
if (linked) {
|
|
7565
|
+
try {
|
|
7566
|
+
symlinkSync(entry.source.target, dest, "junction");
|
|
7567
|
+
} catch {
|
|
7568
|
+
opts.onProgress?.(t("plugin_install.symlink_failed"));
|
|
7569
|
+
cpSync(entry.source.target, dest, { recursive: true });
|
|
7570
|
+
linked = false;
|
|
7571
|
+
}
|
|
7572
|
+
} else {
|
|
7573
|
+
renameSync(pluginRoot(entry.source, entry.stagingDir), dest);
|
|
7574
|
+
}
|
|
7575
|
+
records.push({
|
|
7576
|
+
name: entry.name,
|
|
7577
|
+
version: entry.version,
|
|
7578
|
+
source: entry.source.raw,
|
|
7579
|
+
sourceType: entry.source.type,
|
|
7160
7580
|
path: dest,
|
|
7161
|
-
linked
|
|
7581
|
+
linked,
|
|
7162
7582
|
enabled: true,
|
|
7163
7583
|
installedAt: Date.now(),
|
|
7164
|
-
...
|
|
7165
|
-
...source.sha256 ? { checksum: `sha256:${source.sha256}` } : {}
|
|
7166
|
-
};
|
|
7167
|
-
return new PluginStore(opts.statePath).mutate((records) => {
|
|
7168
|
-
const taken = records.some((r) => r.name === name);
|
|
7169
|
-
if (taken && opts.replace !== name) return void 0;
|
|
7170
|
-
return {
|
|
7171
|
-
records: taken ? records.map((r) => r.name === name ? record : r) : [...records, record],
|
|
7172
|
-
result: record
|
|
7173
|
-
};
|
|
7584
|
+
...entry.marketplace ? { marketplace: entry.marketplace } : {},
|
|
7585
|
+
...entry.source.sha256 ? { checksum: `sha256:${entry.source.sha256}` } : {}
|
|
7174
7586
|
});
|
|
7175
7587
|
}
|
|
7588
|
+
return new PluginStore(opts.statePath).mutate((existing) => {
|
|
7589
|
+
for (const record of records) {
|
|
7590
|
+
const taken = existing.some((r) => r.name === record.name);
|
|
7591
|
+
if (taken && opts.replace !== record.name) return void 0;
|
|
7592
|
+
}
|
|
7593
|
+
let next = existing;
|
|
7594
|
+
for (const record of records) {
|
|
7595
|
+
const taken = next.some((r) => r.name === record.name);
|
|
7596
|
+
next = taken ? next.map((r) => r.name === record.name ? record : r) : [...next, record];
|
|
7597
|
+
}
|
|
7598
|
+
return { records: next, result: records };
|
|
7599
|
+
});
|
|
7600
|
+
}
|
|
7601
|
+
async function resolveClosure(input) {
|
|
7602
|
+
const { opts, staging } = input;
|
|
7603
|
+
const seen = /* @__PURE__ */ new Set([input.root]);
|
|
7604
|
+
const queue = input.declared.map((name) => ({
|
|
7605
|
+
name,
|
|
7606
|
+
requiredBy: input.root
|
|
7607
|
+
}));
|
|
7608
|
+
const report3 = [];
|
|
7609
|
+
const plans = [];
|
|
7610
|
+
while (queue.length > 0) {
|
|
7611
|
+
const next = queue.shift();
|
|
7612
|
+
if (!next) break;
|
|
7613
|
+
const { name, requiredBy } = next;
|
|
7614
|
+
if (seen.has(name)) continue;
|
|
7615
|
+
seen.add(name);
|
|
7616
|
+
if (input.installed.has(name)) {
|
|
7617
|
+
report3.push({ name, status: "installed", requiredBy });
|
|
7618
|
+
continue;
|
|
7619
|
+
}
|
|
7620
|
+
if (plans.length >= DEPENDENCY_LIMIT) {
|
|
7621
|
+
report3.push({
|
|
7622
|
+
name,
|
|
7623
|
+
status: "unresolved",
|
|
7624
|
+
requiredBy,
|
|
7625
|
+
reason: t("plugin_install.dep_too_many", { limit: DEPENDENCY_LIMIT, root: input.root })
|
|
7626
|
+
});
|
|
7627
|
+
continue;
|
|
7628
|
+
}
|
|
7629
|
+
const located = await locateDependency(name, opts);
|
|
7630
|
+
if (!located) {
|
|
7631
|
+
report3.push({
|
|
7632
|
+
name,
|
|
7633
|
+
status: "unresolved",
|
|
7634
|
+
requiredBy,
|
|
7635
|
+
reason: t("plugin_install.dep_no_source", { name })
|
|
7636
|
+
});
|
|
7637
|
+
continue;
|
|
7638
|
+
}
|
|
7639
|
+
const source = resolveSource(located.source);
|
|
7640
|
+
if (!source) {
|
|
7641
|
+
report3.push({
|
|
7642
|
+
name,
|
|
7643
|
+
status: "unresolved",
|
|
7644
|
+
requiredBy,
|
|
7645
|
+
source: located.source,
|
|
7646
|
+
reason: t("plugin_install.dep_bad_source", { name, source: located.source })
|
|
7647
|
+
});
|
|
7648
|
+
continue;
|
|
7649
|
+
}
|
|
7650
|
+
opts.onProgress?.(t("plugin_install.dep_fetching", { name, source: located.source }));
|
|
7651
|
+
const stagingDir = join(staging, `dep-${plans.length}`);
|
|
7652
|
+
const fetched = await fetchInto(source, stagingDir, opts);
|
|
7653
|
+
if (!fetched.ok) {
|
|
7654
|
+
report3.push({
|
|
7655
|
+
name,
|
|
7656
|
+
status: "unresolved",
|
|
7657
|
+
requiredBy,
|
|
7658
|
+
source: located.source,
|
|
7659
|
+
reason: fetched.reason
|
|
7660
|
+
});
|
|
7661
|
+
continue;
|
|
7662
|
+
}
|
|
7663
|
+
const readDir = source.type === "local" ? source.target : pluginRoot(source, stagingDir);
|
|
7664
|
+
const read = readPluginManifest(readDir);
|
|
7665
|
+
const manifest = read.manifest;
|
|
7666
|
+
if (!manifest) {
|
|
7667
|
+
report3.push({
|
|
7668
|
+
name,
|
|
7669
|
+
status: "unresolved",
|
|
7670
|
+
requiredBy,
|
|
7671
|
+
source: located.source,
|
|
7672
|
+
reason: t("plugin_install.dep_bad_manifest", {
|
|
7673
|
+
name,
|
|
7674
|
+
detail: read.issues.map((issue) => issue.message).join("; ")
|
|
7675
|
+
})
|
|
7676
|
+
});
|
|
7677
|
+
continue;
|
|
7678
|
+
}
|
|
7679
|
+
if (manifest.name !== name) {
|
|
7680
|
+
report3.push({
|
|
7681
|
+
name,
|
|
7682
|
+
status: "unresolved",
|
|
7683
|
+
requiredBy,
|
|
7684
|
+
source: located.source,
|
|
7685
|
+
reason: t("plugin_install.dep_name_mismatch", { name, found: manifest.name })
|
|
7686
|
+
});
|
|
7687
|
+
continue;
|
|
7688
|
+
}
|
|
7689
|
+
const current = opts.epochVersion ?? currentEpochVersion();
|
|
7690
|
+
const version = checkEpochVersion(manifest.epochVersion, current);
|
|
7691
|
+
const versionUnmet = !version.ok && manifest.epochVersion ? { required: manifest.epochVersion, current, reason: version.reason } : void 0;
|
|
7692
|
+
report3.push({
|
|
7693
|
+
name,
|
|
7694
|
+
status: "plan",
|
|
7695
|
+
requiredBy,
|
|
7696
|
+
source: located.source,
|
|
7697
|
+
manifest,
|
|
7698
|
+
inventory: scanPluginDir(readDir, manifest.name),
|
|
7699
|
+
...versionUnmet ? { versionUnmet } : {}
|
|
7700
|
+
});
|
|
7701
|
+
plans.push({
|
|
7702
|
+
name: manifest.name,
|
|
7703
|
+
source,
|
|
7704
|
+
stagingDir,
|
|
7705
|
+
manifest,
|
|
7706
|
+
...located.marketplace ? { marketplace: located.marketplace } : {}
|
|
7707
|
+
});
|
|
7708
|
+
for (const nested of manifest.dependencies ?? []) {
|
|
7709
|
+
queue.push({ name: nested, requiredBy: manifest.name });
|
|
7710
|
+
}
|
|
7711
|
+
}
|
|
7712
|
+
return { report: report3, plans };
|
|
7713
|
+
}
|
|
7714
|
+
async function locateDependency(name, opts) {
|
|
7715
|
+
const local = opts.marketplacesStatePath ? findMarketplaceEntryByName(name, opts.marketplacesStatePath) : void 0;
|
|
7716
|
+
if (local) return { source: local.source, marketplace: local.marketplace };
|
|
7717
|
+
if (!opts.resolveDependency) return void 0;
|
|
7718
|
+
try {
|
|
7719
|
+
const answer = await opts.resolveDependency(name);
|
|
7720
|
+
return answer ? { source: answer } : void 0;
|
|
7721
|
+
} catch {
|
|
7722
|
+
return void 0;
|
|
7723
|
+
}
|
|
7176
7724
|
}
|
|
7177
7725
|
function removeInstallDest(dest) {
|
|
7178
7726
|
let link = false;
|
|
@@ -7236,469 +7784,153 @@ async function fetchFromHost(source, staging, opts) {
|
|
|
7236
7784
|
reason: t("plugin_install.host_fetch_no_file", { path: answer.archivePath })
|
|
7237
7785
|
};
|
|
7238
7786
|
}
|
|
7239
|
-
return extractArchive(answer.archivePath, staging);
|
|
7240
|
-
});
|
|
7241
|
-
}
|
|
7242
|
-
function fetchLocal(source) {
|
|
7243
|
-
if (!existsSync(source.target)) {
|
|
7244
|
-
return { ok: false, reason: t("plugin_install.local_missing", { path: source.target }) };
|
|
7245
|
-
}
|
|
7246
|
-
return { ok: true };
|
|
7247
|
-
}
|
|
7248
|
-
async function fetchGit(source, staging, opts) {
|
|
7249
|
-
opts.onProgress?.(t("plugin_install.cloning", { target: source.target }));
|
|
7250
|
-
const result = await runCommand("git", ["clone", "--depth", "1", source.target, staging]);
|
|
7251
|
-
if (!result.ok) {
|
|
7252
|
-
return { ok: false, reason: t("plugin_install.clone_failed", { detail: result.detail }) };
|
|
7253
|
-
}
|
|
7254
|
-
rmSync(join(staging, ".git"), { recursive: true, force: true });
|
|
7255
|
-
return { ok: true };
|
|
7256
|
-
}
|
|
7257
|
-
async function fetchNpm(source, staging, opts) {
|
|
7258
|
-
opts.onProgress?.(t("plugin_install.npm_fetching", { target: source.target }));
|
|
7259
|
-
mkdirSync(staging, { recursive: true });
|
|
7260
|
-
return withDownloadDir(async (dl) => {
|
|
7261
|
-
const packed = await runCommand(
|
|
7262
|
-
"npm",
|
|
7263
|
-
["pack", source.target, "--pack-destination", dl, "--silent"],
|
|
7264
|
-
{ cwd: dl, windowsShell: true }
|
|
7265
|
-
);
|
|
7266
|
-
if (!packed.ok) {
|
|
7267
|
-
return { ok: false, reason: t("plugin_install.npm_pack_failed", { detail: packed.detail }) };
|
|
7268
|
-
}
|
|
7269
|
-
const tarball = packed.stdout.trim().split("\n").pop()?.trim();
|
|
7270
|
-
if (!tarball) return { ok: false, reason: t("plugin_install.npm_no_tarball") };
|
|
7271
|
-
return extractArchive(isAbsolute(tarball) ? tarball : join(dl, tarball), staging);
|
|
7272
|
-
});
|
|
7273
|
-
}
|
|
7274
|
-
async function fetchArchive(source, staging, opts) {
|
|
7275
|
-
opts.onProgress?.(t("plugin_install.downloading", { target: source.target }));
|
|
7276
|
-
mkdirSync(staging, { recursive: true });
|
|
7277
|
-
let bytes;
|
|
7278
|
-
try {
|
|
7279
|
-
const response = await fetch(source.target, { redirect: "follow" });
|
|
7280
|
-
if (!response.ok) {
|
|
7281
|
-
return {
|
|
7282
|
-
ok: false,
|
|
7283
|
-
reason: t("plugin_install.download_http", {
|
|
7284
|
-
status: response.status,
|
|
7285
|
-
statusText: response.statusText
|
|
7286
|
-
})
|
|
7287
|
-
};
|
|
7288
|
-
}
|
|
7289
|
-
bytes = Buffer.from(await response.arrayBuffer());
|
|
7290
|
-
} catch (err) {
|
|
7291
|
-
return {
|
|
7292
|
-
ok: false,
|
|
7293
|
-
reason: t("plugin_install.download_failed", {
|
|
7294
|
-
message: err instanceof Error ? err.message : String(err)
|
|
7295
|
-
})
|
|
7296
|
-
};
|
|
7297
|
-
}
|
|
7298
|
-
if (source.sha256) {
|
|
7299
|
-
const actual = createHash("sha256").update(bytes).digest("hex");
|
|
7300
|
-
if (actual !== source.sha256) {
|
|
7301
|
-
return {
|
|
7302
|
-
ok: false,
|
|
7303
|
-
reason: [
|
|
7304
|
-
t("plugin_install.sha_mismatch"),
|
|
7305
|
-
t("plugin_install.sha_expected", { expected: source.sha256 }),
|
|
7306
|
-
t("plugin_install.sha_actual", { actual })
|
|
7307
|
-
].join("\n")
|
|
7308
|
-
};
|
|
7309
|
-
}
|
|
7310
|
-
}
|
|
7311
|
-
return withDownloadDir(async (dl) => {
|
|
7312
|
-
const archive = join(dl, `download${archiveExt(source.target)}`);
|
|
7313
|
-
writeFileSync(archive, bytes);
|
|
7314
|
-
return extractArchive(archive, staging);
|
|
7315
|
-
});
|
|
7316
|
-
}
|
|
7317
|
-
function archiveExt(url) {
|
|
7318
|
-
const path = (url.split("?")[0] ?? "").toLowerCase();
|
|
7319
|
-
if (path.endsWith(".tgz")) return ".tgz";
|
|
7320
|
-
if (path.endsWith(".tar.gz")) return ".tar.gz";
|
|
7321
|
-
return ".zip";
|
|
7322
|
-
}
|
|
7323
|
-
async function withDownloadDir(fn) {
|
|
7324
|
-
const dir = mkdtempSync(join(tmpdir(), "epoch-plugin-dl-"));
|
|
7325
|
-
try {
|
|
7326
|
-
return await fn(dir);
|
|
7327
|
-
} finally {
|
|
7328
|
-
rmSync(dir, { recursive: true, force: true });
|
|
7329
|
-
}
|
|
7330
|
-
}
|
|
7331
|
-
// src/plugin/root-token.ts
|
|
7332
|
-
var PLUGIN_ROOT_TOKEN = "${EPOCH_PLUGIN_ROOT}";
|
|
7333
|
-
var PLUGIN_ROOT_ENV = "EPOCH_PLUGIN_ROOT";
|
|
7334
|
-
function mentionsPluginRoot(text) {
|
|
7335
|
-
return text.includes(PLUGIN_ROOT_TOKEN);
|
|
7336
|
-
}
|
|
7337
|
-
function substitutePluginRoot(text, root) {
|
|
7338
|
-
return text.split(PLUGIN_ROOT_TOKEN).join(root);
|
|
7339
|
-
}
|
|
7340
|
-
async function uninstallPlugin(name, opts) {
|
|
7341
|
-
const removed = await new PluginStore(opts.statePath).mutate((records) => {
|
|
7342
|
-
const hit = records.find((r) => r.name === name);
|
|
7343
|
-
if (!hit) return void 0;
|
|
7344
|
-
return { records: records.filter((r) => r.name !== name), result: hit };
|
|
7345
|
-
});
|
|
7346
|
-
if (!removed) return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7347
|
-
if (removed.linked) {
|
|
7348
|
-
rmSync(removed.path, { force: true });
|
|
7349
|
-
return { ok: true, message: t("plugin_lifecycle.uninstalled_link", { name }) };
|
|
7350
|
-
}
|
|
7351
|
-
rmSync(removed.path, { recursive: true, force: true });
|
|
7352
|
-
return { ok: true, message: t("plugin_lifecycle.uninstalled", { name }) };
|
|
7353
|
-
}
|
|
7354
|
-
async function setPluginEnabled(name, enabled, opts) {
|
|
7355
|
-
const changed = await new PluginStore(opts.statePath).mutate((records) => {
|
|
7356
|
-
const hit = records.find((r) => r.name === name);
|
|
7357
|
-
if (!hit) return void 0;
|
|
7358
|
-
return {
|
|
7359
|
-
records: records.map((r) => r.name === name ? { ...r, enabled } : r),
|
|
7360
|
-
result: hit.enabled !== enabled
|
|
7361
|
-
};
|
|
7362
|
-
});
|
|
7363
|
-
if (changed === void 0) {
|
|
7364
|
-
return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7365
|
-
}
|
|
7366
|
-
const verb = enabled ? t("plugin_lifecycle.verb_enable") : t("plugin_lifecycle.verb_disable");
|
|
7367
|
-
return {
|
|
7368
|
-
ok: true,
|
|
7369
|
-
message: changed ? t("plugin_lifecycle.toggled", { verb, name }) : t("plugin_lifecycle.already", { name, verb })
|
|
7370
|
-
};
|
|
7371
|
-
}
|
|
7372
|
-
async function updatePlugin(name, opts) {
|
|
7373
|
-
const existing = new PluginStore(opts.statePath).read().records.find((r) => r.name === name);
|
|
7374
|
-
if (!existing) return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7375
|
-
if (existing.linked) {
|
|
7376
|
-
return {
|
|
7377
|
-
ok: true,
|
|
7378
|
-
message: t("plugin_lifecycle.linked_no_update", { name, source: existing.source })
|
|
7379
|
-
};
|
|
7380
|
-
}
|
|
7381
|
-
return installPlugin(existing.source, {
|
|
7382
|
-
...opts,
|
|
7383
|
-
replace: name,
|
|
7384
|
-
...existing.marketplace ? { marketplace: existing.marketplace } : {}
|
|
7385
|
-
});
|
|
7386
|
-
}
|
|
7387
|
-
var MARKETPLACE_FILE = "epoch-marketplace.json";
|
|
7388
|
-
var NAME_PATTERN = PLUGIN_NAME_PATTERN;
|
|
7389
|
-
var EntryCategoryInput = z.union([z.string().min(1), z.array(z.string().min(1))]).optional().catch(void 0);
|
|
7390
|
-
var EntryShape = z.object({
|
|
7391
|
-
name: z.string().regex(NAME_PATTERN),
|
|
7392
|
-
description: z.string().min(1).optional(),
|
|
7393
|
-
source: z.string().min(1),
|
|
7394
|
-
category: EntryCategoryInput,
|
|
7395
|
-
keywords: z.array(z.string().min(1)).optional(),
|
|
7396
|
-
author: PluginAuthorSchema.optional(),
|
|
7397
|
-
downloads: z.number().int().nonnegative().optional(),
|
|
7398
|
-
likes: z.number().int().nonnegative().optional(),
|
|
7399
|
-
displayName: z.string().min(1).optional(),
|
|
7400
|
-
icon: z.string().min(1).optional(),
|
|
7401
|
-
version: z.string().min(1).optional(),
|
|
7402
|
-
changelog: z.string().min(1).optional(),
|
|
7403
|
-
size: z.number().int().positive().optional(),
|
|
7404
|
-
homepage: z.string().min(1).optional(),
|
|
7405
|
-
visibility: z.enum(PLUGIN_VISIBILITY).optional().catch(void 0),
|
|
7406
|
-
status: z.enum(["listed", "reviewing", "rejected", "offline"]).optional().catch(void 0)
|
|
7407
|
-
});
|
|
7408
|
-
var EntrySchema = EntryShape.transform(({ category, ...rest }) => {
|
|
7409
|
-
const picked = category === void 0 ? [] : typeof category === "string" ? [category] : category;
|
|
7410
|
-
return { ...rest, ...picked.length === 0 ? {} : { category: [...picked] } };
|
|
7411
|
-
});
|
|
7412
|
-
var MARKETPLACE_DISPLAY_FIELDS = [
|
|
7413
|
-
"status",
|
|
7414
|
-
"downloads",
|
|
7415
|
-
"likes",
|
|
7416
|
-
"author",
|
|
7417
|
-
"category",
|
|
7418
|
-
"visibility",
|
|
7419
|
-
"icon",
|
|
7420
|
-
"homepage",
|
|
7421
|
-
"size"
|
|
7422
|
-
];
|
|
7423
|
-
var DisplaySchema = z.object({
|
|
7424
|
-
fields: z.array(z.string().min(1)).optional()
|
|
7425
|
-
});
|
|
7426
|
-
var CategoryNodeSchema = z.lazy(
|
|
7427
|
-
() => z.object({
|
|
7428
|
-
id: z.string().min(1),
|
|
7429
|
-
label: z.string().min(1).optional(),
|
|
7430
|
-
children: z.array(CategoryNodeSchema).optional()
|
|
7431
|
-
})
|
|
7432
|
-
);
|
|
7433
|
-
var CategoriesSchema = z.array(CategoryNodeSchema).refine(hasUniqueCategoryIds, { message: "category ids must be unique across the whole tree" }).optional().catch(void 0);
|
|
7434
|
-
function hasUniqueCategoryIds(nodes) {
|
|
7435
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7436
|
-
const walk3 = (list) => list.every((node) => {
|
|
7437
|
-
if (seen.has(node.id)) return false;
|
|
7438
|
-
seen.add(node.id);
|
|
7439
|
-
return node.children === void 0 || walk3(node.children);
|
|
7440
|
-
});
|
|
7441
|
-
return walk3(nodes);
|
|
7442
|
-
}
|
|
7443
|
-
var CatalogSchema = z.object({
|
|
7444
|
-
name: z.string().regex(NAME_PATTERN),
|
|
7445
|
-
description: z.string().min(1).optional(),
|
|
7446
|
-
owner: z.object({ name: z.string().min(1), url: z.string().min(1).optional() }).optional(),
|
|
7447
|
-
display: DisplaySchema.optional(),
|
|
7448
|
-
categories: CategoriesSchema,
|
|
7449
|
-
plugins: z.array(EntrySchema)
|
|
7450
|
-
});
|
|
7451
|
-
var RecordSchema2 = z.object({
|
|
7452
|
-
name: z.string().regex(NAME_PATTERN),
|
|
7453
|
-
source: z.string().min(1),
|
|
7454
|
-
addedAt: z.number(),
|
|
7455
|
-
catalog: CatalogSchema
|
|
7456
|
-
});
|
|
7457
|
-
var StateSchema2 = z.object({
|
|
7458
|
-
version: z.literal(1).optional(),
|
|
7459
|
-
marketplaces: z.array(RecordSchema2)
|
|
7460
|
-
});
|
|
7461
|
-
function projectEntryForDisplay(entry, display) {
|
|
7462
|
-
const allowed = display?.fields;
|
|
7463
|
-
if (allowed === void 0) return entry;
|
|
7464
|
-
const out = { ...entry };
|
|
7465
|
-
for (const field of MARKETPLACE_DISPLAY_FIELDS) {
|
|
7466
|
-
if (!displayAllows(display, field)) delete out[field];
|
|
7467
|
-
}
|
|
7468
|
-
return out;
|
|
7469
|
-
}
|
|
7470
|
-
function displayAllows(display, field) {
|
|
7471
|
-
const allowed = display?.fields;
|
|
7472
|
-
if (allowed === void 0) return true;
|
|
7473
|
-
return allowed.includes(field);
|
|
7474
|
-
}
|
|
7475
|
-
function readMarketplaces(statePath) {
|
|
7476
|
-
if (!existsSync(statePath)) return { records: [], issues: [] };
|
|
7477
|
-
let raw;
|
|
7478
|
-
try {
|
|
7479
|
-
raw = JSON.parse(readFileSync(statePath, "utf-8"));
|
|
7480
|
-
} catch (err) {
|
|
7481
|
-
return {
|
|
7482
|
-
records: [],
|
|
7483
|
-
issues: [
|
|
7484
|
-
{ path: statePath, message: t("plugin_marketplace.bad_json", { reason: first(err) }) }
|
|
7485
|
-
]
|
|
7486
|
-
};
|
|
7487
|
-
}
|
|
7488
|
-
const checked = parseLenient(StateSchema2.optional(), raw, void 0);
|
|
7489
|
-
if (!checked.value) {
|
|
7490
|
-
return {
|
|
7491
|
-
records: [],
|
|
7492
|
-
issues: checked.issues.map((i) => ({
|
|
7493
|
-
path: statePath,
|
|
7494
|
-
message: t("plugin_marketplace.issue", { path: i.path, message: i.message })
|
|
7495
|
-
}))
|
|
7496
|
-
};
|
|
7497
|
-
}
|
|
7498
|
-
return { records: checked.value.marketplaces, issues: [] };
|
|
7499
|
-
}
|
|
7500
|
-
async function mutate(statePath, fn) {
|
|
7501
|
-
const release = await acquireStateLock(statePath);
|
|
7502
|
-
try {
|
|
7503
|
-
const next = fn(readMarketplaces(statePath).records);
|
|
7504
|
-
if (!next) return false;
|
|
7505
|
-
writeStateFile(statePath, JSON.stringify({ version: 1, marketplaces: next }, null, 2));
|
|
7506
|
-
return true;
|
|
7507
|
-
} finally {
|
|
7508
|
-
release();
|
|
7509
|
-
}
|
|
7510
|
-
}
|
|
7511
|
-
async function addMarketplace(source, opts) {
|
|
7512
|
-
const fetched = await fetchCatalog(source);
|
|
7513
|
-
if (!fetched.ok) return fetched;
|
|
7514
|
-
const record = {
|
|
7515
|
-
name: fetched.catalog.name,
|
|
7516
|
-
source: source.trim(),
|
|
7517
|
-
addedAt: Date.now(),
|
|
7518
|
-
catalog: fetched.catalog
|
|
7519
|
-
};
|
|
7520
|
-
const written = await mutate(
|
|
7521
|
-
opts.statePath,
|
|
7522
|
-
(records) => records.some((r) => r.name === record.name) ? void 0 : [...records, record].sort((a, b) => a.name.localeCompare(b.name))
|
|
7523
|
-
);
|
|
7524
|
-
return written ? { ok: true, record } : {
|
|
7525
|
-
ok: false,
|
|
7526
|
-
reason: t("plugin_marketplace.already_added", { name: record.name })
|
|
7527
|
-
};
|
|
7528
|
-
}
|
|
7529
|
-
async function removeMarketplace(name, opts) {
|
|
7530
|
-
const written = await mutate(
|
|
7531
|
-
opts.statePath,
|
|
7532
|
-
(records) => records.some((r) => r.name === name) ? records.filter((r) => r.name !== name) : void 0
|
|
7533
|
-
);
|
|
7534
|
-
return written ? { ok: true } : { ok: false, reason: t("plugin_marketplace.not_added", { name }) };
|
|
7535
|
-
}
|
|
7536
|
-
async function updateMarketplace(name, opts) {
|
|
7537
|
-
const existing = readMarketplaces(opts.statePath).records.find((r) => r.name === name);
|
|
7538
|
-
if (!existing) return { ok: false, reason: t("plugin_marketplace.not_added", { name }) };
|
|
7539
|
-
const fetched = await fetchCatalog(existing.source);
|
|
7540
|
-
if (!fetched.ok) return fetched;
|
|
7541
|
-
if (fetched.catalog.name !== name) {
|
|
7542
|
-
return {
|
|
7543
|
-
ok: false,
|
|
7544
|
-
reason: t("plugin_marketplace.renamed", {
|
|
7545
|
-
source: existing.source,
|
|
7546
|
-
name: fetched.catalog.name
|
|
7547
|
-
})
|
|
7548
|
-
};
|
|
7549
|
-
}
|
|
7550
|
-
const record = { ...existing, catalog: fetched.catalog };
|
|
7551
|
-
await mutate(opts.statePath, (records) => records.map((r) => r.name === name ? record : r));
|
|
7552
|
-
return { ok: true, record };
|
|
7553
|
-
}
|
|
7554
|
-
function searchMarketplaces(keyword, statePath) {
|
|
7555
|
-
const needle = keyword.trim().toLowerCase();
|
|
7556
|
-
const hits = [];
|
|
7557
|
-
for (const record of readMarketplaces(statePath).records) {
|
|
7558
|
-
for (const entry of record.catalog.plugins) {
|
|
7559
|
-
const haystack = [
|
|
7560
|
-
entry.name,
|
|
7561
|
-
entry.description ?? "",
|
|
7562
|
-
...entry.category ?? [],
|
|
7563
|
-
entry.author?.name ?? "",
|
|
7564
|
-
...entry.keywords ?? []
|
|
7565
|
-
].join(" ").toLowerCase();
|
|
7566
|
-
if (needle && !haystack.includes(needle)) continue;
|
|
7567
|
-
hits.push({
|
|
7568
|
-
marketplace: record.name,
|
|
7569
|
-
entry: projectEntryForDisplay(entry, record.catalog.display),
|
|
7570
|
-
ref: `${record.name}/${entry.name}`
|
|
7571
|
-
});
|
|
7572
|
-
}
|
|
7573
|
-
}
|
|
7574
|
-
return hits;
|
|
7575
|
-
}
|
|
7576
|
-
function resolveMarketplaceRef(input, statePath) {
|
|
7577
|
-
const parts = input.trim().split("/");
|
|
7578
|
-
if (parts.length !== 2) return void 0;
|
|
7579
|
-
const [market = "", plugin = ""] = parts;
|
|
7580
|
-
if (!NAME_PATTERN.test(market) || !NAME_PATTERN.test(plugin)) return void 0;
|
|
7581
|
-
const record = readMarketplaces(statePath).records.find((r) => r.name === market);
|
|
7582
|
-
if (!record) {
|
|
7583
|
-
return {
|
|
7584
|
-
ok: false,
|
|
7585
|
-
reason: t("plugin_marketplace.market_not_added", { market, input })
|
|
7586
|
-
};
|
|
7587
|
-
}
|
|
7588
|
-
const entry = record.catalog.plugins.find((p) => p.name === plugin);
|
|
7589
|
-
if (!entry) {
|
|
7590
|
-
return {
|
|
7591
|
-
ok: false,
|
|
7592
|
-
reason: t("plugin_marketplace.plugin_not_in_market", { market, plugin })
|
|
7593
|
-
};
|
|
7594
|
-
}
|
|
7595
|
-
const source = resolveEntrySource(entry.source, record.source);
|
|
7596
|
-
if (!source) {
|
|
7597
|
-
return {
|
|
7598
|
-
ok: false,
|
|
7599
|
-
reason: t("plugin_marketplace.entry_unresolvable", {
|
|
7600
|
-
market,
|
|
7601
|
-
plugin,
|
|
7602
|
-
source: entry.source
|
|
7603
|
-
})
|
|
7604
|
-
};
|
|
7605
|
-
}
|
|
7606
|
-
return { ok: true, ref: { marketplace: market, source } };
|
|
7607
|
-
}
|
|
7608
|
-
function resolveEntrySource(entry, marketSource) {
|
|
7609
|
-
const spec = entry.trim();
|
|
7610
|
-
if (!spec.startsWith(".") && !spec.startsWith("/")) return spec;
|
|
7611
|
-
const rel = spec.replace(/^\.\//, "").replace(/^\//, "");
|
|
7612
|
-
if (rel === "" || rel.split("/").includes("..")) return void 0;
|
|
7613
|
-
const market = marketSource.trim();
|
|
7614
|
-
if (market.startsWith("github:") || market.startsWith("git+")) {
|
|
7615
|
-
const [base = "", fragment] = market.split("#", 2);
|
|
7616
|
-
const prefix = fragment?.startsWith("subdir=") ? `${fragment.slice("subdir=".length)}/` : "";
|
|
7617
|
-
return `${base}#subdir=${prefix}${rel}`;
|
|
7787
|
+
return extractArchive(answer.archivePath, staging);
|
|
7788
|
+
});
|
|
7789
|
+
}
|
|
7790
|
+
function fetchLocal(source) {
|
|
7791
|
+
if (!existsSync(source.target)) {
|
|
7792
|
+
return { ok: false, reason: t("plugin_install.local_missing", { path: source.target }) };
|
|
7618
7793
|
}
|
|
7619
|
-
|
|
7620
|
-
|
|
7794
|
+
return { ok: true };
|
|
7795
|
+
}
|
|
7796
|
+
async function fetchGit(source, staging, opts) {
|
|
7797
|
+
opts.onProgress?.(t("plugin_install.cloning", { target: source.target }));
|
|
7798
|
+
const result = await runCommand("git", ["clone", "--depth", "1", source.target, staging]);
|
|
7799
|
+
if (!result.ok) {
|
|
7800
|
+
return { ok: false, reason: t("plugin_install.clone_failed", { detail: result.detail }) };
|
|
7621
7801
|
}
|
|
7622
|
-
|
|
7802
|
+
rmSync(join(staging, ".git"), { recursive: true, force: true });
|
|
7803
|
+
return { ok: true };
|
|
7623
7804
|
}
|
|
7624
|
-
async function
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7805
|
+
async function fetchNpm(source, staging, opts) {
|
|
7806
|
+
opts.onProgress?.(t("plugin_install.npm_fetching", { target: source.target }));
|
|
7807
|
+
mkdirSync(staging, { recursive: true });
|
|
7808
|
+
return withDownloadDir(async (dl) => {
|
|
7809
|
+
const packed = await runCommand(
|
|
7810
|
+
"npm",
|
|
7811
|
+
["pack", source.target, "--pack-destination", dl, "--silent"],
|
|
7812
|
+
{ cwd: dl, windowsShell: true }
|
|
7813
|
+
);
|
|
7814
|
+
if (!packed.ok) {
|
|
7815
|
+
return { ok: false, reason: t("plugin_install.npm_pack_failed", { detail: packed.detail }) };
|
|
7631
7816
|
}
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7817
|
+
const tarball = packed.stdout.trim().split("\n").pop()?.trim();
|
|
7818
|
+
if (!tarball) return { ok: false, reason: t("plugin_install.npm_no_tarball") };
|
|
7819
|
+
return extractArchive(isAbsolute(tarball) ? tarball : join(dl, tarball), staging);
|
|
7820
|
+
});
|
|
7821
|
+
}
|
|
7822
|
+
async function fetchArchive(source, staging, opts) {
|
|
7823
|
+
opts.onProgress?.(t("plugin_install.downloading", { target: source.target }));
|
|
7824
|
+
mkdirSync(staging, { recursive: true });
|
|
7825
|
+
let bytes;
|
|
7826
|
+
try {
|
|
7827
|
+
const response = await fetch(source.target, { redirect: "follow" });
|
|
7828
|
+
if (!response.ok) {
|
|
7829
|
+
return {
|
|
7830
|
+
ok: false,
|
|
7831
|
+
reason: t("plugin_install.download_http", {
|
|
7832
|
+
status: response.status,
|
|
7833
|
+
statusText: response.statusText
|
|
7834
|
+
})
|
|
7835
|
+
};
|
|
7636
7836
|
}
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
if (!url) {
|
|
7837
|
+
bytes = Buffer.from(await response.arrayBuffer());
|
|
7838
|
+
} catch (err) {
|
|
7640
7839
|
return {
|
|
7641
7840
|
ok: false,
|
|
7642
|
-
reason: t("
|
|
7841
|
+
reason: t("plugin_install.download_failed", {
|
|
7842
|
+
message: err instanceof Error ? err.message : String(err)
|
|
7843
|
+
})
|
|
7643
7844
|
};
|
|
7644
7845
|
}
|
|
7645
|
-
|
|
7646
|
-
const
|
|
7647
|
-
if (
|
|
7648
|
-
const vars = { url, status: response.status };
|
|
7846
|
+
if (source.sha256) {
|
|
7847
|
+
const actual = createHash("sha256").update(bytes).digest("hex");
|
|
7848
|
+
if (actual !== source.sha256) {
|
|
7649
7849
|
return {
|
|
7650
7850
|
ok: false,
|
|
7651
|
-
reason:
|
|
7851
|
+
reason: [
|
|
7852
|
+
t("plugin_install.sha_mismatch"),
|
|
7853
|
+
t("plugin_install.sha_expected", { expected: source.sha256 }),
|
|
7854
|
+
t("plugin_install.sha_actual", { actual })
|
|
7855
|
+
].join("\n")
|
|
7652
7856
|
};
|
|
7653
7857
|
}
|
|
7654
|
-
return parseCatalog(await response.text(), url);
|
|
7655
|
-
} catch (err) {
|
|
7656
|
-
return { ok: false, reason: t("marketplace.fetch_error", { url, reason: first(err) }) };
|
|
7657
7858
|
}
|
|
7859
|
+
return withDownloadDir(async (dl) => {
|
|
7860
|
+
const archive = join(dl, `download${archiveExt(source.target)}`);
|
|
7861
|
+
writeFileSync(archive, bytes);
|
|
7862
|
+
return extractArchive(archive, staging);
|
|
7863
|
+
});
|
|
7658
7864
|
}
|
|
7659
|
-
function
|
|
7660
|
-
|
|
7865
|
+
function archiveExt(url) {
|
|
7866
|
+
const path = (url.split("?")[0] ?? "").toLowerCase();
|
|
7867
|
+
if (path.endsWith(".tgz")) return ".tgz";
|
|
7868
|
+
if (path.endsWith(".tar.gz")) return ".tar.gz";
|
|
7869
|
+
return ".zip";
|
|
7661
7870
|
}
|
|
7662
|
-
function
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7871
|
+
async function withDownloadDir(fn) {
|
|
7872
|
+
const dir = mkdtempSync(join(tmpdir(), "epoch-plugin-dl-"));
|
|
7873
|
+
try {
|
|
7874
|
+
return await fn(dir);
|
|
7875
|
+
} finally {
|
|
7876
|
+
rmSync(dir, { recursive: true, force: true });
|
|
7667
7877
|
}
|
|
7668
|
-
if (!input.startsWith("https://") && !input.startsWith("http://")) return void 0;
|
|
7669
|
-
return input.endsWith(".json") ? input : `${input.replace(/\/+$/, "")}/${MARKETPLACE_FILE}`;
|
|
7670
7878
|
}
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
return
|
|
7879
|
+
// src/plugin/root-token.ts
|
|
7880
|
+
var PLUGIN_ROOT_TOKEN = "${EPOCH_PLUGIN_ROOT}";
|
|
7881
|
+
var PLUGIN_ROOT_ENV = "EPOCH_PLUGIN_ROOT";
|
|
7882
|
+
function mentionsPluginRoot(text) {
|
|
7883
|
+
return text.includes(PLUGIN_ROOT_TOKEN);
|
|
7676
7884
|
}
|
|
7677
|
-
function
|
|
7678
|
-
|
|
7679
|
-
if (existsSync(abs) && statSync(abs).isDirectory()) return abs;
|
|
7680
|
-
return abs.replace(/[/\\][^/\\]*$/, "");
|
|
7885
|
+
function substitutePluginRoot(text, root) {
|
|
7886
|
+
return text.split(PLUGIN_ROOT_TOKEN).join(root);
|
|
7681
7887
|
}
|
|
7682
|
-
function
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7888
|
+
async function uninstallPlugin(name, opts) {
|
|
7889
|
+
const removed = await new PluginStore(opts.statePath).mutate((records) => {
|
|
7890
|
+
const hit = records.find((r) => r.name === name);
|
|
7891
|
+
if (!hit) return void 0;
|
|
7892
|
+
return { records: records.filter((r) => r.name !== name), result: hit };
|
|
7893
|
+
});
|
|
7894
|
+
if (!removed) return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7895
|
+
if (removed.linked) {
|
|
7896
|
+
rmSync(removed.path, { force: true });
|
|
7897
|
+
return { ok: true, message: t("plugin_lifecycle.uninstalled_link", { name }) };
|
|
7898
|
+
}
|
|
7899
|
+
rmSync(removed.path, { recursive: true, force: true });
|
|
7900
|
+
return { ok: true, message: t("plugin_lifecycle.uninstalled", { name }) };
|
|
7901
|
+
}
|
|
7902
|
+
async function setPluginEnabled(name, enabled, opts) {
|
|
7903
|
+
const changed = await new PluginStore(opts.statePath).mutate((records) => {
|
|
7904
|
+
const hit = records.find((r) => r.name === name);
|
|
7905
|
+
if (!hit) return void 0;
|
|
7687
7906
|
return {
|
|
7688
|
-
|
|
7689
|
-
|
|
7907
|
+
records: records.map((r) => r.name === name ? { ...r, enabled } : r),
|
|
7908
|
+
result: hit.enabled !== enabled
|
|
7690
7909
|
};
|
|
7910
|
+
});
|
|
7911
|
+
if (changed === void 0) {
|
|
7912
|
+
return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7691
7913
|
}
|
|
7692
|
-
const
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
}
|
|
7697
|
-
return { ok: true, catalog: checked.value };
|
|
7914
|
+
const verb = enabled ? t("plugin_lifecycle.verb_enable") : t("plugin_lifecycle.verb_disable");
|
|
7915
|
+
return {
|
|
7916
|
+
ok: true,
|
|
7917
|
+
message: changed ? t("plugin_lifecycle.toggled", { verb, name }) : t("plugin_lifecycle.already", { name, verb })
|
|
7918
|
+
};
|
|
7698
7919
|
}
|
|
7699
|
-
function
|
|
7700
|
-
const
|
|
7701
|
-
|
|
7920
|
+
async function updatePlugin(name, opts) {
|
|
7921
|
+
const existing = new PluginStore(opts.statePath).read().records.find((r) => r.name === name);
|
|
7922
|
+
if (!existing) return { ok: false, reason: t("plugin_lifecycle.not_installed", { name }) };
|
|
7923
|
+
if (existing.linked) {
|
|
7924
|
+
return {
|
|
7925
|
+
ok: true,
|
|
7926
|
+
message: t("plugin_lifecycle.linked_no_update", { name, source: existing.source })
|
|
7927
|
+
};
|
|
7928
|
+
}
|
|
7929
|
+
return installPlugin(existing.source, {
|
|
7930
|
+
...opts,
|
|
7931
|
+
replace: name,
|
|
7932
|
+
...existing.marketplace ? { marketplace: existing.marketplace } : {}
|
|
7933
|
+
});
|
|
7702
7934
|
}
|
|
7703
7935
|
var TMP_SUFFIX = ".epoch-rewind";
|
|
7704
7936
|
function planFor(entry, current) {
|
|
@@ -7746,7 +7978,7 @@ async function applyRewind(store, sessionId, manifest, apply, skippedConflicts)
|
|
|
7746
7978
|
} catch (err) {
|
|
7747
7979
|
return { ...empty, failed: t("rewind.stage_failed", { message: messageOf(err) }) };
|
|
7748
7980
|
}
|
|
7749
|
-
return
|
|
7981
|
+
return commitAll2(staged, skippedConflicts);
|
|
7750
7982
|
}
|
|
7751
7983
|
async function stageAll(store, sessionId, manifest, todo, byPath) {
|
|
7752
7984
|
const staged = [];
|
|
@@ -7774,7 +8006,7 @@ async function stageAll(store, sessionId, manifest, todo, byPath) {
|
|
|
7774
8006
|
}
|
|
7775
8007
|
return staged;
|
|
7776
8008
|
}
|
|
7777
|
-
async function
|
|
8009
|
+
async function commitAll2(staged, skippedConflicts) {
|
|
7778
8010
|
const outcome = {
|
|
7779
8011
|
restored: [],
|
|
7780
8012
|
deleted: [],
|
|
@@ -7931,14 +8163,14 @@ var CheckpointStore = class {
|
|
|
7931
8163
|
}
|
|
7932
8164
|
async enforceTotalSize(protectSession, protectTurnIndex) {
|
|
7933
8165
|
const turns = await this.collectTurns();
|
|
7934
|
-
let total = turns.reduce((sum,
|
|
8166
|
+
let total = turns.reduce((sum, t81) => sum + t81.bytes, 0);
|
|
7935
8167
|
if (total <= this.maxTotalBytes) return;
|
|
7936
8168
|
turns.sort((a, b) => a.createdAt - b.createdAt);
|
|
7937
|
-
for (const
|
|
8169
|
+
for (const t81 of turns) {
|
|
7938
8170
|
if (total <= this.maxTotalBytes) return;
|
|
7939
|
-
if (
|
|
7940
|
-
await this.removeTurn(
|
|
7941
|
-
total -=
|
|
8171
|
+
if (t81.sessionId === protectSession && t81.turnIndex === protectTurnIndex) continue;
|
|
8172
|
+
await this.removeTurn(t81.sessionId, t81.turnIndex);
|
|
8173
|
+
total -= t81.bytes;
|
|
7942
8174
|
}
|
|
7943
8175
|
}
|
|
7944
8176
|
async collectTurns() {
|
|
@@ -10739,11 +10971,11 @@ var PromptBuilder = class {
|
|
|
10739
10971
|
memoryInitialized = false;
|
|
10740
10972
|
projectBlock(tools) {
|
|
10741
10973
|
const permLevel = this.deps.permissionManager?.getLevel() || "default";
|
|
10742
|
-
const hasPlanTool = tools.some((
|
|
10743
|
-
const hasLspTool = tools.some((
|
|
10744
|
-
const hasAskTool = tools.some((
|
|
10745
|
-
const hasTodoTool = tools.some((
|
|
10746
|
-
const hasTerminal = tools.some((
|
|
10974
|
+
const hasPlanTool = tools.some((t81) => t81.name === "enter_plan_mode");
|
|
10975
|
+
const hasLspTool = tools.some((t81) => t81.name === "lsp_diagnostics");
|
|
10976
|
+
const hasAskTool = tools.some((t81) => t81.name === "ask_user_question");
|
|
10977
|
+
const hasTodoTool = tools.some((t81) => t81.name === "todo");
|
|
10978
|
+
const hasTerminal = tools.some((t81) => t81.name === "terminal");
|
|
10747
10979
|
const needsCommandApproval = hasTerminal && permLevel === "default";
|
|
10748
10980
|
const plan = this.deps.approvedPlan?.()?.trim();
|
|
10749
10981
|
const codeSdk = renderSdkDeclaration(this.deps.codeModeTools?.() ?? []);
|
|
@@ -11433,8 +11665,8 @@ function imageParts(content) {
|
|
|
11433
11665
|
return typeof content === "string" ? [] : content.filter((p) => p.type === "image");
|
|
11434
11666
|
}
|
|
11435
11667
|
function toolSignatureOf(config, tools) {
|
|
11436
|
-
const direct = tools.map((
|
|
11437
|
-
const declared = (config.codeModeTools?.() ?? []).map((
|
|
11668
|
+
const direct = tools.map((t81) => t81.name).join("\0");
|
|
11669
|
+
const declared = (config.codeModeTools?.() ?? []).map((t81) => t81.name).join("\0");
|
|
11438
11670
|
return declared ? `${direct}|${declared}` : direct;
|
|
11439
11671
|
}
|
|
11440
11672
|
function modelSignatureOf(info) {
|
|
@@ -12982,8 +13214,10 @@ function _loadImpl(overrideHomeDir) {
|
|
|
12982
13214
|
return cached.config;
|
|
12983
13215
|
}
|
|
12984
13216
|
const config = parseRawConfig(read.raw, issues, track);
|
|
12985
|
-
const
|
|
13217
|
+
const override = readProviderOverride(issues);
|
|
13218
|
+
const pinned = applyProviderOverride(config, track, override);
|
|
12986
13219
|
const secretSource = applySecretsFromEnv(config, homeDir, track);
|
|
13220
|
+
if (pinned) applyProviderOverride(config, track, override);
|
|
12987
13221
|
applyEnvOverrides(config, issues, track);
|
|
12988
13222
|
if (secretSource === "config-file" && !pinned) detectProviderFromKey(config);
|
|
12989
13223
|
if (overrideHomeDir) {
|
|
@@ -13054,19 +13288,30 @@ function applySecretsFromEnv(config, homeDir, track) {
|
|
|
13054
13288
|
}
|
|
13055
13289
|
return "config-file";
|
|
13056
13290
|
}
|
|
13057
|
-
function
|
|
13058
|
-
const
|
|
13059
|
-
|
|
13060
|
-
|
|
13061
|
-
|
|
13291
|
+
function readProviderOverride(issues) {
|
|
13292
|
+
const override = {};
|
|
13293
|
+
const baseUrl = process.env.EPOCH_BASE_URL;
|
|
13294
|
+
if (baseUrl) {
|
|
13295
|
+
override.baseUrl = baseUrl;
|
|
13296
|
+
override.type = "openai-compatible";
|
|
13062
13297
|
}
|
|
13063
13298
|
const type = process.env.EPOCH_PROVIDER;
|
|
13064
|
-
if (
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13299
|
+
if (type) {
|
|
13300
|
+
if (isProviderType(type)) {
|
|
13301
|
+
override.type ??= type;
|
|
13302
|
+
} else {
|
|
13303
|
+
issues.push(envIssue("EPOCH_PROVIDER", type, PROVIDER_TYPES.join(" / ")));
|
|
13304
|
+
}
|
|
13305
|
+
}
|
|
13306
|
+
return override;
|
|
13307
|
+
}
|
|
13308
|
+
function applyProviderOverride(config, track, override) {
|
|
13309
|
+
if (override.baseUrl) {
|
|
13310
|
+
config.provider.baseUrl = override.baseUrl;
|
|
13311
|
+
track.env.add("provider.baseUrl");
|
|
13068
13312
|
}
|
|
13069
|
-
|
|
13313
|
+
if (!override.type) return false;
|
|
13314
|
+
config.provider.type = override.type;
|
|
13070
13315
|
track.env.add("provider.type");
|
|
13071
13316
|
return true;
|
|
13072
13317
|
}
|
|
@@ -13326,6 +13571,10 @@ var DEFAULT_MODELS = {
|
|
|
13326
13571
|
groq: "llama-3.3-70b-versatile",
|
|
13327
13572
|
mistral: "ministral-8b-latest",
|
|
13328
13573
|
moonshotai: "kimi-latest",
|
|
13574
|
+
zhipu: "glm-4.5-flash",
|
|
13575
|
+
dashscope: "qwen-flash",
|
|
13576
|
+
bytedance: "doubao-seed-2.0-mini",
|
|
13577
|
+
qianfan: "ernie-speed-128k",
|
|
13329
13578
|
cohere: "command-r7b-12-2024",
|
|
13330
13579
|
xai: "grok-vision-beta",
|
|
13331
13580
|
perplexity: "sonar",
|
|
@@ -13738,6 +13987,10 @@ var PACKAGES = {
|
|
|
13738
13987
|
groq: "@ai-sdk/groq",
|
|
13739
13988
|
mistral: "@ai-sdk/mistral",
|
|
13740
13989
|
moonshotai: "@ai-sdk/moonshotai",
|
|
13990
|
+
zhipu: "@ai-sdk/openai-compatible",
|
|
13991
|
+
dashscope: "@ai-sdk/alibaba",
|
|
13992
|
+
bytedance: "@ai-sdk/openai-compatible",
|
|
13993
|
+
qianfan: "@ai-sdk/openai-compatible",
|
|
13741
13994
|
cohere: "@ai-sdk/cohere",
|
|
13742
13995
|
xai: "@ai-sdk/xai",
|
|
13743
13996
|
perplexity: "@ai-sdk/perplexity",
|
|
@@ -13747,6 +14000,17 @@ var PACKAGES = {
|
|
|
13747
14000
|
ollama: "ollama-ai-provider-v2",
|
|
13748
14001
|
"openai-compatible": "@ai-sdk/openai-compatible"
|
|
13749
14002
|
};
|
|
14003
|
+
function openaiCompatibleFactory(name, defaultBaseUrl) {
|
|
14004
|
+
return async ({ apiKey, baseUrl }) => {
|
|
14005
|
+
const { createOpenAICompatible } = await import('@ai-sdk/openai-compatible');
|
|
14006
|
+
return createOpenAICompatible({
|
|
14007
|
+
apiKey,
|
|
14008
|
+
baseURL: baseUrl || defaultBaseUrl,
|
|
14009
|
+
name,
|
|
14010
|
+
includeUsage: true
|
|
14011
|
+
});
|
|
14012
|
+
};
|
|
14013
|
+
}
|
|
13750
14014
|
var LOADERS = {
|
|
13751
14015
|
openai: async ({ apiKey, baseUrl }) => {
|
|
13752
14016
|
const { createOpenAI } = await import('@ai-sdk/openai');
|
|
@@ -13778,6 +14042,17 @@ var LOADERS = {
|
|
|
13778
14042
|
const { createMoonshotAI } = await import('@ai-sdk/moonshotai');
|
|
13779
14043
|
return createMoonshotAI({ apiKey });
|
|
13780
14044
|
},
|
|
14045
|
+
zhipu: openaiCompatibleFactory("zhipu", "https://open.bigmodel.cn/api/paas/v4"),
|
|
14046
|
+
dashscope: async ({ apiKey, baseUrl }) => {
|
|
14047
|
+
const { createAlibaba } = await import('@ai-sdk/alibaba');
|
|
14048
|
+
const provider = createAlibaba({
|
|
14049
|
+
apiKey,
|
|
14050
|
+
baseURL: baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
14051
|
+
});
|
|
14052
|
+
return (model) => provider.languageModel(model);
|
|
14053
|
+
},
|
|
14054
|
+
bytedance: openaiCompatibleFactory("bytedance", "https://ark.cn-beijing.volces.com/api/v3"),
|
|
14055
|
+
qianfan: openaiCompatibleFactory("qianfan", "https://qianfan.baidubce.com/v2"),
|
|
13781
14056
|
cohere: async ({ apiKey }) => {
|
|
13782
14057
|
const { createCohere } = await import('@ai-sdk/cohere');
|
|
13783
14058
|
return createCohere({ apiKey });
|
|
@@ -13806,15 +14081,7 @@ var LOADERS = {
|
|
|
13806
14081
|
const { createOllama } = await import('ollama-ai-provider-v2');
|
|
13807
14082
|
return createOllama();
|
|
13808
14083
|
},
|
|
13809
|
-
"openai-compatible":
|
|
13810
|
-
const { createOpenAICompatible } = await import('@ai-sdk/openai-compatible');
|
|
13811
|
-
return createOpenAICompatible({
|
|
13812
|
-
apiKey,
|
|
13813
|
-
baseURL: baseUrl || "http://localhost:8080/v1",
|
|
13814
|
-
name: "custom",
|
|
13815
|
-
includeUsage: true
|
|
13816
|
-
});
|
|
13817
|
-
}
|
|
14084
|
+
"openai-compatible": openaiCompatibleFactory("custom", "http://localhost:8080/v1")
|
|
13818
14085
|
};
|
|
13819
14086
|
var ProviderSdkMissingError = class extends Error {
|
|
13820
14087
|
constructor(providerType, packageName, cause) {
|
|
@@ -14446,6 +14713,10 @@ var STATIC_MODEL_CATALOG = {
|
|
|
14446
14713
|
],
|
|
14447
14714
|
mistral: ["mistral-large-latest", "mistral-small-latest", "codestral-latest"],
|
|
14448
14715
|
moonshotai: ["kimi-latest"],
|
|
14716
|
+
zhipu: ["glm-4.6", "glm-4.5-flash", "glm-4.5-air", "glm-4.5"],
|
|
14717
|
+
dashscope: ["qwen3-max", "qwen-plus", "qwen-flash", "qwen-turbo", "qwen-max-latest"],
|
|
14718
|
+
bytedance: ["doubao-seed-2.1-pro", "doubao-seed-2.0-mini", "doubao-seed-1.6-flash"],
|
|
14719
|
+
qianfan: ["ernie-5.0", "ernie-speed-128k", "ernie-4.0-turbo-8k"],
|
|
14449
14720
|
cohere: ["command-r-plus-04-2024", "command-r7b-12-2024", "command-a-03-2025"],
|
|
14450
14721
|
xai: ["grok-vision-beta"],
|
|
14451
14722
|
perplexity: ["sonar", "sonar-pro", "sonar-reasoning"],
|
|
@@ -14461,6 +14732,10 @@ var PROVIDER_DISCOVERY = {
|
|
|
14461
14732
|
groq: { baseUrl: "https://api.groq.com/openai/v1", auth: "bearer" },
|
|
14462
14733
|
mistral: { baseUrl: "https://api.mistral.ai/v1", auth: "bearer" },
|
|
14463
14734
|
moonshotai: { baseUrl: "https://api.moonshot.ai/v1", auth: "bearer" },
|
|
14735
|
+
zhipu: { baseUrl: "https://open.bigmodel.cn/api/paas/v4", auth: "bearer" },
|
|
14736
|
+
dashscope: { baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1", auth: "bearer" },
|
|
14737
|
+
bytedance: { baseUrl: "https://ark.cn-beijing.volces.com/api/v3", auth: "bearer" },
|
|
14738
|
+
qianfan: { baseUrl: "https://qianfan.baidubce.com/v2", auth: "bearer" },
|
|
14464
14739
|
xai: { baseUrl: "https://api.x.ai/v1", auth: "bearer" },
|
|
14465
14740
|
perplexity: { baseUrl: "https://api.perplexity.ai", auth: "bearer" },
|
|
14466
14741
|
togetherai: { baseUrl: "https://api.together.xyz/v1", auth: "bearer" }
|
|
@@ -14711,7 +14986,7 @@ function writeUserYaml(path, key, value) {
|
|
|
14711
14986
|
const after = asMapping(parseYaml(next));
|
|
14712
14987
|
const intact = after !== null && (dot < 0 ? onlyChanged(before, after, key, value) : onlyChangedNested(before, after, key.slice(0, dot), key.slice(dot + 1), value));
|
|
14713
14988
|
if (!intact) return { ok: false, reason: "unwritable-file" };
|
|
14714
|
-
return
|
|
14989
|
+
return commit(path, next, 384, value);
|
|
14715
14990
|
}
|
|
14716
14991
|
function writeSettingsJson(path, key, value) {
|
|
14717
14992
|
let before = {};
|
|
@@ -14731,7 +15006,7 @@ function writeSettingsJson(path, key, value) {
|
|
|
14731
15006
|
}
|
|
14732
15007
|
const body2 = `${JSON.stringify({ ...before, [key]: value }, null, 2)}
|
|
14733
15008
|
`;
|
|
14734
|
-
return
|
|
15009
|
+
return commit(path, body2, 420, value);
|
|
14735
15010
|
}
|
|
14736
15011
|
function scalarText(value) {
|
|
14737
15012
|
return dump(value, { lineWidth: -1 }).trimEnd();
|
|
@@ -14788,7 +15063,7 @@ function sameKeysAndValues(before, after, except) {
|
|
|
14788
15063
|
function sameData(a, b) {
|
|
14789
15064
|
return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
|
|
14790
15065
|
}
|
|
14791
|
-
function
|
|
15066
|
+
function commit(path, body2, createMode, value) {
|
|
14792
15067
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
14793
15068
|
try {
|
|
14794
15069
|
mkdirSync(dirname(path), { recursive: true });
|
|
@@ -15079,11 +15354,11 @@ function buildSearchQuery(query) {
|
|
|
15079
15354
|
}
|
|
15080
15355
|
const latinPart = cleaned.replace(CJK_RUN, " ");
|
|
15081
15356
|
for (const w of latinPart.split(/\s+/)) {
|
|
15082
|
-
const
|
|
15083
|
-
if (
|
|
15357
|
+
const t81 = w.trim();
|
|
15358
|
+
if (t81.length >= 2) terms.add(t81);
|
|
15084
15359
|
}
|
|
15085
15360
|
if (terms.size === 0) return null;
|
|
15086
|
-
return [...terms].map((
|
|
15361
|
+
return [...terms].map((t81) => `"${t81.replace(/"/g, "")}"`).join(" OR ");
|
|
15087
15362
|
}
|
|
15088
15363
|
// src/memory/db.ts
|
|
15089
15364
|
var NS2 = "memory";
|
|
@@ -17102,7 +17377,7 @@ function checkFtsHealth(db) {
|
|
|
17102
17377
|
messages,
|
|
17103
17378
|
tables,
|
|
17104
17379
|
missingTriggers,
|
|
17105
|
-
healthy: missingTriggers.length === 0 && tables.every((
|
|
17380
|
+
healthy: missingTriggers.length === 0 && tables.every((t81) => t81.error === null && t81.drift === null && t81.rows === messages),
|
|
17106
17381
|
indexBytes: indexBytesOf(db),
|
|
17107
17382
|
space: spaceOf(db)
|
|
17108
17383
|
};
|
|
@@ -18196,6 +18471,72 @@ function isLastOpenSession(value) {
|
|
|
18196
18471
|
const v = value;
|
|
18197
18472
|
return typeof v["root"] === "string" && v["root"].length > 0 && typeof v["sessionId"] === "string" && v["sessionId"].length > 0 && typeof v["at"] === "number";
|
|
18198
18473
|
}
|
|
18474
|
+
var FILE_VERSION4 = 1;
|
|
18475
|
+
function describe8(err) {
|
|
18476
|
+
return err instanceof Error ? err.message : String(err);
|
|
18477
|
+
}
|
|
18478
|
+
var AppearanceStore = class {
|
|
18479
|
+
constructor(filePath = appearancePath()) {
|
|
18480
|
+
this.filePath = filePath;
|
|
18481
|
+
this.load();
|
|
18482
|
+
}
|
|
18483
|
+
filePath;
|
|
18484
|
+
prefs = {};
|
|
18485
|
+
loadErrors = [];
|
|
18486
|
+
writeErrors = [];
|
|
18487
|
+
get() {
|
|
18488
|
+
return { ...this.prefs };
|
|
18489
|
+
}
|
|
18490
|
+
set(patch) {
|
|
18491
|
+
const next = { ...this.prefs };
|
|
18492
|
+
for (const key of ["theme", "lang"]) {
|
|
18493
|
+
const value = patch[key];
|
|
18494
|
+
if (typeof value === "string" && value.length > 0) next[key] = value;
|
|
18495
|
+
}
|
|
18496
|
+
if (next.theme === this.prefs.theme && next.lang === this.prefs.lang) return;
|
|
18497
|
+
this.prefs = next;
|
|
18498
|
+
this.save();
|
|
18499
|
+
}
|
|
18500
|
+
load() {
|
|
18501
|
+
this.prefs = {};
|
|
18502
|
+
if (!existsSync(this.filePath)) return;
|
|
18503
|
+
let parsed;
|
|
18504
|
+
try {
|
|
18505
|
+
parsed = JSON.parse(readFileSync(this.filePath, "utf-8"));
|
|
18506
|
+
} catch (err) {
|
|
18507
|
+
this.loadErrors.push(
|
|
18508
|
+
(lang) => t("appearance.unreadable", { path: this.filePath, reason: describe8(err) }, lang)
|
|
18509
|
+
);
|
|
18510
|
+
return;
|
|
18511
|
+
}
|
|
18512
|
+
this.adopt(parsed);
|
|
18513
|
+
}
|
|
18514
|
+
adopt(parsed) {
|
|
18515
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return;
|
|
18516
|
+
const file = parsed;
|
|
18517
|
+
if (file.version !== FILE_VERSION4) return;
|
|
18518
|
+
if (typeof file.theme === "string" && file.theme.length > 0) this.prefs.theme = file.theme;
|
|
18519
|
+
if (typeof file.lang === "string" && file.lang.length > 0) this.prefs.lang = file.lang;
|
|
18520
|
+
}
|
|
18521
|
+
save() {
|
|
18522
|
+
const body2 = JSON.stringify(
|
|
18523
|
+
{ version: FILE_VERSION4, ...this.prefs },
|
|
18524
|
+
null,
|
|
18525
|
+
2
|
|
18526
|
+
);
|
|
18527
|
+
const tmp = `${this.filePath}.${process.pid}.tmp`;
|
|
18528
|
+
try {
|
|
18529
|
+
mkdirSync(dirname(this.filePath), { recursive: true });
|
|
18530
|
+
writeFileSync(tmp, body2, { encoding: "utf-8", mode: 384 });
|
|
18531
|
+
renameSync(tmp, this.filePath);
|
|
18532
|
+
} catch (err) {
|
|
18533
|
+
rmSync(tmp, { force: true });
|
|
18534
|
+
this.writeErrors.push(
|
|
18535
|
+
(lang) => t("appearance.write_failed", { path: this.filePath, reason: describe8(err) }, lang)
|
|
18536
|
+
);
|
|
18537
|
+
}
|
|
18538
|
+
}
|
|
18539
|
+
};
|
|
18199
18540
|
function ruleAskActive(level) {
|
|
18200
18541
|
return level !== "bypass";
|
|
18201
18542
|
}
|
|
@@ -18446,11 +18787,11 @@ var ApprovalCache = class {
|
|
|
18446
18787
|
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
18447
18788
|
}
|
|
18448
18789
|
normalizeTarget(target) {
|
|
18449
|
-
const
|
|
18450
|
-
if (!
|
|
18451
|
-
const unix =
|
|
18790
|
+
const t81 = target.trim();
|
|
18791
|
+
if (!t81) return "";
|
|
18792
|
+
const unix = t81.replace(/\\/g, "/");
|
|
18452
18793
|
if (unix.startsWith("/") || /^[A-Za-z]:\//.test(unix)) return resolve(unix);
|
|
18453
|
-
return
|
|
18794
|
+
return t81;
|
|
18454
18795
|
}
|
|
18455
18796
|
load() {
|
|
18456
18797
|
try {
|
|
@@ -18553,9 +18894,9 @@ function createSharedPermissionState(cache) {
|
|
|
18553
18894
|
};
|
|
18554
18895
|
}
|
|
18555
18896
|
function cacheKeyFor(raw) {
|
|
18556
|
-
const
|
|
18557
|
-
if (!
|
|
18558
|
-
return
|
|
18897
|
+
const t81 = raw.trim();
|
|
18898
|
+
if (!t81) return null;
|
|
18899
|
+
return t81.slice(0, 500);
|
|
18559
18900
|
}
|
|
18560
18901
|
// src/permission/manager.ts
|
|
18561
18902
|
var log3 = createLogger("permission");
|
|
@@ -19854,7 +20195,7 @@ function parseSimpleToml(content, file) {
|
|
|
19854
20195
|
const at = `${file}:${i + 1}`;
|
|
19855
20196
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
19856
20197
|
if (trimmed === "[[rule]]") {
|
|
19857
|
-
if (current)
|
|
20198
|
+
if (current) commit2(current, file, rules, issues);
|
|
19858
20199
|
current = { raw: {}, line: i + 1 };
|
|
19859
20200
|
continue;
|
|
19860
20201
|
}
|
|
@@ -19877,7 +20218,7 @@ function parseSimpleToml(content, file) {
|
|
|
19877
20218
|
current.raw[kv.key] = kv.value;
|
|
19878
20219
|
}
|
|
19879
20220
|
}
|
|
19880
|
-
if (current)
|
|
20221
|
+
if (current) commit2(current, file, rules, issues);
|
|
19881
20222
|
return { rules, issues };
|
|
19882
20223
|
}
|
|
19883
20224
|
function readKeyValue(line) {
|
|
@@ -19891,7 +20232,7 @@ function readKeyValue(line) {
|
|
|
19891
20232
|
const sq = rawVal.match(/^'(.*)'$/);
|
|
19892
20233
|
return { key, value: sq && sq[1] ? sq[1] : rawVal };
|
|
19893
20234
|
}
|
|
19894
|
-
function
|
|
20235
|
+
function commit2(draft, file, rules, issues) {
|
|
19895
20236
|
const at = `${file}:${draft.line}`;
|
|
19896
20237
|
issues.push(...unknownKeyIssues(POLICY_RULE_KEYS, draft.raw, at));
|
|
19897
20238
|
const raw = { ...draft.raw };
|
|
@@ -20985,7 +21326,7 @@ var HookManager = class {
|
|
|
20985
21326
|
return { blocked: true, reason: result.rejectReason || t("hook_load.rejected") };
|
|
20986
21327
|
}
|
|
20987
21328
|
} catch (err) {
|
|
20988
|
-
this.log("warn", `[HookManager] ${type} \u7684 command hook \u6267\u884C\u5F02\u5E38: ${
|
|
21329
|
+
this.log("warn", `[HookManager] ${type} \u7684 command hook \u6267\u884C\u5F02\u5E38: ${describe10(err)}`, {
|
|
20989
21330
|
hookType: type,
|
|
20990
21331
|
command: config.command
|
|
20991
21332
|
});
|
|
@@ -21003,7 +21344,7 @@ var HookManager = class {
|
|
|
21003
21344
|
(_, reject2) => setTimeout(() => reject2(new Error("Hook timeout")), HOOK_TIMEOUT_MS)
|
|
21004
21345
|
)
|
|
21005
21346
|
]).catch((err) => {
|
|
21006
|
-
this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${
|
|
21347
|
+
this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${describe10(err)}`, {
|
|
21007
21348
|
hookType: type,
|
|
21008
21349
|
plugin: reg.plugin
|
|
21009
21350
|
});
|
|
@@ -21015,7 +21356,7 @@ var HookManager = class {
|
|
|
21015
21356
|
if (!matchesHook(entry.matcher, event)) continue;
|
|
21016
21357
|
for (const config of entry.configs) {
|
|
21017
21358
|
runCommandHook(config, event, ctx.workDir).then((result) => reportIfNeverRan(this.log, type, config, result)).catch((err) => {
|
|
21018
|
-
this.log("warn", `[HookManager] ${type} \u7684 command hook \u5F02\u6B65\u5F02\u5E38: ${
|
|
21359
|
+
this.log("warn", `[HookManager] ${type} \u7684 command hook \u5F02\u6B65\u5F02\u5E38: ${describe10(err)}`, {
|
|
21019
21360
|
hookType: type,
|
|
21020
21361
|
command: config.command
|
|
21021
21362
|
});
|
|
@@ -21036,7 +21377,7 @@ var HookManager = class {
|
|
|
21036
21377
|
]);
|
|
21037
21378
|
if (result !== null && result !== void 0) return result;
|
|
21038
21379
|
} catch (err) {
|
|
21039
|
-
this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${
|
|
21380
|
+
this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${describe10(err)}`, {
|
|
21040
21381
|
hookType: type,
|
|
21041
21382
|
plugin: reg.plugin
|
|
21042
21383
|
});
|
|
@@ -21057,7 +21398,7 @@ var HookManager = class {
|
|
|
21057
21398
|
]);
|
|
21058
21399
|
if (result) results.push(result);
|
|
21059
21400
|
} catch (err) {
|
|
21060
|
-
this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${
|
|
21401
|
+
this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${describe10(err)}`, {
|
|
21061
21402
|
hookType: type,
|
|
21062
21403
|
plugin: reg.plugin
|
|
21063
21404
|
});
|
|
@@ -21074,7 +21415,7 @@ var HookManager = class {
|
|
|
21074
21415
|
const verdict = verdictOf2(result);
|
|
21075
21416
|
if (verdict) results.push(verdict);
|
|
21076
21417
|
} catch (err) {
|
|
21077
|
-
this.log("warn", `[HookManager] ${type} \u7684 command hook \u6267\u884C\u5F02\u5E38: ${
|
|
21418
|
+
this.log("warn", `[HookManager] ${type} \u7684 command hook \u6267\u884C\u5F02\u5E38: ${describe10(err)}`, {
|
|
21078
21419
|
hookType: type,
|
|
21079
21420
|
command: config.command
|
|
21080
21421
|
});
|
|
@@ -21090,7 +21431,7 @@ var HookManager = class {
|
|
|
21090
21431
|
return [...list].sort((a, b) => a.priority - b.priority);
|
|
21091
21432
|
}
|
|
21092
21433
|
};
|
|
21093
|
-
function
|
|
21434
|
+
function describe10(err) {
|
|
21094
21435
|
return err instanceof Error ? err.message : String(err);
|
|
21095
21436
|
}
|
|
21096
21437
|
function verdictOf2(result) {
|
|
@@ -22379,7 +22720,7 @@ async function importSkills(source, opts) {
|
|
|
22379
22720
|
detail: t("skill.import_stale", void 0, opts.lang)
|
|
22380
22721
|
};
|
|
22381
22722
|
}
|
|
22382
|
-
return { ok: true, ...
|
|
22723
|
+
return { ok: true, ...commit3(preview3, staged, opts.skillsDir, opts.lang) };
|
|
22383
22724
|
});
|
|
22384
22725
|
}
|
|
22385
22726
|
async function withStaged(source, opts, fn) {
|
|
@@ -22413,7 +22754,7 @@ async function withStaged(source, opts, fn) {
|
|
|
22413
22754
|
shape = existsSync(join(unpacked, SKILL_FILE)) ? "skill-dir" : "tree";
|
|
22414
22755
|
}
|
|
22415
22756
|
const staged = stageImport(root, staging, shape, opts.lang);
|
|
22416
|
-
const preview3 =
|
|
22757
|
+
const preview3 = describe11(source, form, staged.skills, staged.issues, opts.existing, opts.lang);
|
|
22417
22758
|
if (preview3.skills.length === 0) {
|
|
22418
22759
|
const detail = t("skill.import_empty", { path: source }, opts.lang);
|
|
22419
22760
|
return { ok: false, reason: "empty", detail, issues: preview3.issues };
|
|
@@ -22424,7 +22765,7 @@ async function withStaged(source, opts, fn) {
|
|
|
22424
22765
|
rmSync(unpacked, { recursive: true, force: true });
|
|
22425
22766
|
}
|
|
22426
22767
|
}
|
|
22427
|
-
function
|
|
22768
|
+
function describe11(source, form, staged, issues, existing, lang) {
|
|
22428
22769
|
const byName = new Map(existing.map((s) => [s.name, s.scope]));
|
|
22429
22770
|
const entries2 = [];
|
|
22430
22771
|
const taken = /* @__PURE__ */ new Set();
|
|
@@ -22498,7 +22839,7 @@ function digest(entries2, staged) {
|
|
|
22498
22839
|
}
|
|
22499
22840
|
return hash.digest("hex").slice(0, 32);
|
|
22500
22841
|
}
|
|
22501
|
-
function
|
|
22842
|
+
function commit3(preview3, staged, skillsDir, lang) {
|
|
22502
22843
|
const byName = new Map(staged.map((s) => [s.name, s.dir]));
|
|
22503
22844
|
const imported = [];
|
|
22504
22845
|
const skipped = [];
|
|
@@ -23273,10 +23614,10 @@ ${extra}` : withGoal;
|
|
|
23273
23614
|
return messages.reduce((sum, m) => sum + estimateTokens(m.content), 0);
|
|
23274
23615
|
}
|
|
23275
23616
|
};
|
|
23276
|
-
var
|
|
23617
|
+
var FILE_VERSION5 = 1;
|
|
23277
23618
|
var LEVELS = ["trusted", "untrusted"];
|
|
23278
23619
|
var SCOPES = ["directory", "directory-tree"];
|
|
23279
|
-
function
|
|
23620
|
+
function describe12(err) {
|
|
23280
23621
|
return err instanceof Error ? err.message : String(err);
|
|
23281
23622
|
}
|
|
23282
23623
|
function covers(base, target, scope) {
|
|
@@ -23350,7 +23691,7 @@ var TrustManager = class {
|
|
|
23350
23691
|
raw = readFileSync(this.filePath, "utf-8");
|
|
23351
23692
|
} catch (err) {
|
|
23352
23693
|
this.loadErrors.push(
|
|
23353
|
-
t("trust_gate.record_read_failed", { path: this.filePath, reason:
|
|
23694
|
+
t("trust_gate.record_read_failed", { path: this.filePath, reason: describe12(err) })
|
|
23354
23695
|
);
|
|
23355
23696
|
return;
|
|
23356
23697
|
}
|
|
@@ -23359,7 +23700,7 @@ var TrustManager = class {
|
|
|
23359
23700
|
parsed = JSON.parse(raw);
|
|
23360
23701
|
} catch (err) {
|
|
23361
23702
|
this.loadErrors.push(
|
|
23362
|
-
t("trust_gate.record_bad_json", { path: this.filePath, reason:
|
|
23703
|
+
t("trust_gate.record_bad_json", { path: this.filePath, reason: describe12(err) })
|
|
23363
23704
|
);
|
|
23364
23705
|
return;
|
|
23365
23706
|
}
|
|
@@ -23371,12 +23712,12 @@ var TrustManager = class {
|
|
|
23371
23712
|
return;
|
|
23372
23713
|
}
|
|
23373
23714
|
const file = parsed;
|
|
23374
|
-
if (file.version !==
|
|
23715
|
+
if (file.version !== FILE_VERSION5) {
|
|
23375
23716
|
this.loadErrors.push(
|
|
23376
23717
|
t("trust_gate.record_bad_version", {
|
|
23377
23718
|
path: this.filePath,
|
|
23378
23719
|
found: String(file.version),
|
|
23379
|
-
expected:
|
|
23720
|
+
expected: FILE_VERSION5
|
|
23380
23721
|
})
|
|
23381
23722
|
);
|
|
23382
23723
|
return;
|
|
@@ -23397,7 +23738,7 @@ var TrustManager = class {
|
|
|
23397
23738
|
save() {
|
|
23398
23739
|
mkdirSync(dirname(this.filePath), { recursive: true });
|
|
23399
23740
|
const body2 = JSON.stringify(
|
|
23400
|
-
{ version:
|
|
23741
|
+
{ version: FILE_VERSION5, records: this.records },
|
|
23401
23742
|
null,
|
|
23402
23743
|
2
|
|
23403
23744
|
);
|
|
@@ -23408,7 +23749,7 @@ var TrustManager = class {
|
|
|
23408
23749
|
} catch (err) {
|
|
23409
23750
|
rmSync(tmp, { force: true });
|
|
23410
23751
|
throw new Error(
|
|
23411
|
-
t("trust_gate.record_write_failed", { path: this.filePath, reason:
|
|
23752
|
+
t("trust_gate.record_write_failed", { path: this.filePath, reason: describe12(err) })
|
|
23412
23753
|
);
|
|
23413
23754
|
}
|
|
23414
23755
|
}
|
|
@@ -23797,4 +24138,4 @@ function trunc(stdout, stderr) {
|
|
|
23797
24138
|
* `--tree` 的命令帮助里,让用户自己知道 `--tree` 意味着什么。
|
|
23798
24139
|
*/
|
|
23799
24140
|
|
|
23800
|
-
export { AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, ATTACHMENT_MAX_TOTAL_BYTES, ATTACHMENT_RETENTION_DEFAULTS, AgentLoop, 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 };
|
|
24141
|
+
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 };
|