@epoch-agent/core 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +38 -2
- package/dist/index.js +83 -7
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -11791,6 +11791,14 @@ declare const EpochConfigSchema: z.ZodObject<{
|
|
|
11791
11791
|
label: z.ZodString;
|
|
11792
11792
|
icon: z.ZodOptional<z.ZodString>;
|
|
11793
11793
|
}, z.core.$strip>>;
|
|
11794
|
+
settingsHidden: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
11795
|
+
settingsPanes: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
11796
|
+
id: z.ZodString;
|
|
11797
|
+
label: z.ZodString;
|
|
11798
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
11799
|
+
url: z.ZodString;
|
|
11800
|
+
before: z.ZodOptional<z.ZodString>;
|
|
11801
|
+
}, z.core.$strip>>>;
|
|
11794
11802
|
}, z.core.$strip>;
|
|
11795
11803
|
/**
|
|
11796
11804
|
* 全默认配置 —— 从 schema 派生,不是第二份字面量。
|
|
@@ -16964,8 +16972,8 @@ type BackendOutcome = {
|
|
|
16964
16972
|
/**
|
|
16965
16973
|
* OS 侧那条任务此刻的样子。`null` = 那儿没有这条任务。
|
|
16966
16974
|
*
|
|
16967
|
-
*
|
|
16968
|
-
*
|
|
16975
|
+
* `commandLine` / `spec` 都是**给 `doctor` 比对用的字符串**,不是结构 —— 两个平台
|
|
16976
|
+
* 能拿到的东西形状完全不同(Windows 是 `schtasks /Query` 的一行文本,macOS 是我们
|
|
16969
16977
|
* 自己写的那份 plist),硬拗成同一个结构只会让两边各塞一半空字段。
|
|
16970
16978
|
* 比对的另一半由 `expectedSnapshot()` 用**同一套算法**从库里那行算出来。
|
|
16971
16979
|
*/
|
|
@@ -16973,6 +16981,20 @@ interface OsTaskSnapshot {
|
|
|
16973
16981
|
osTaskId: string;
|
|
16974
16982
|
/** 那条命令行 */
|
|
16975
16983
|
commandLine: string;
|
|
16984
|
+
/**
|
|
16985
|
+
* 同一条命令行**切成段**。
|
|
16986
|
+
*
|
|
16987
|
+
* ⚠️ **它不是 `commandLine` 的便利副本,是一件 `commandLine` 答不了的事。**
|
|
16988
|
+
* `doctor` 判一条孤儿归不归自己管,靠的是命令行里 `--home` 后面那一段
|
|
16989
|
+
* (规矩见 [argv.ts](./argv.ts) 第 2 条:数据目录固化进命令行)。而从拼好的
|
|
16990
|
+
* 那一串里把它切回来,两个平台都不可靠:launchd 那侧 `commandLine` 是
|
|
16991
|
+
* `argv.join(' ')`,home 路径带空格就切不开;Windows 那侧每段带引号,
|
|
16992
|
+
* 按空白切又会把 `"C:\Program Files\..."` 劈成两半。
|
|
16993
|
+
*
|
|
16994
|
+
* 所以由**后端**交出来 —— 它手上有没拼之前的那份:launchd 本来就是数组,
|
|
16995
|
+
* schtasks 用 `taskRunArgv()` 做 `quoteTaskRun()` 的逆。
|
|
16996
|
+
*/
|
|
16997
|
+
argv: string[];
|
|
16976
16998
|
/** 触发规格 */
|
|
16977
16999
|
spec: string;
|
|
16978
17000
|
/** 停用了没有 */
|
|
@@ -17095,6 +17117,15 @@ type RegisterOutcome = {
|
|
|
17095
17117
|
declare class ScheduleRegistrar {
|
|
17096
17118
|
private readonly opts;
|
|
17097
17119
|
constructor(opts: RegistrarOptions);
|
|
17120
|
+
/**
|
|
17121
|
+
* 固化进命令行的那个数据目录。
|
|
17122
|
+
*
|
|
17123
|
+
* **公开出来是给 `doctor` 用的**(同下面 `toRegisterInput` 那一处的理由):
|
|
17124
|
+
* 它要判「OS 侧这条没主的任务是不是我们这个 home 的」,而那个比较的另一头
|
|
17125
|
+
* 必须和注册时真的写进命令行的那个值**同源**。让调用方自己再传一个 home 进来
|
|
17126
|
+
* 的话,两者对不上时不会有任何地方报错 —— 只会安静地把别人的任务判成孤儿。
|
|
17127
|
+
*/
|
|
17128
|
+
get homeDir(): string;
|
|
17098
17129
|
/** 这条任务在 OS 侧叫什么。没有后端时是空串 */
|
|
17099
17130
|
osTaskIdFor(taskId: string): string;
|
|
17100
17131
|
/**
|
|
@@ -17177,6 +17208,11 @@ declare class ScheduleRegistrar {
|
|
|
17177
17208
|
* 第三类的判据要写清楚:**DB 是真源。** 反过来(以 OS 为准)意味着我们要把
|
|
17178
17209
|
* `schtasks` 的时间语法反解析回三档,那是一条只输不赢的路。
|
|
17179
17210
|
*
|
|
17211
|
+
* ⚠️ **第二类先过一道 home 闸**:OS 侧的枚举是刻意跨 home 的,所以「库里没有」
|
|
17212
|
+
* 不等于「没人认领」—— 同一台机器上另一个数据目录(嵌入宿主 / 另一个
|
|
17213
|
+
* `EPOCH_PROFILE`)的活任务也在同一个前缀底下。判据全文在 {@link ownedByThisHome},
|
|
17214
|
+
* 那儿记着它拦下的那次真实误删。
|
|
17215
|
+
*
|
|
17180
17216
|
* ⚠️ **第三类在两个平台上都是逐字比的,而 Windows 那侧曾经不是**(2026-08-18
|
|
17181
17217
|
* 真机那一轮改的)。两头各自归一到同一个串(`DAILY|09:00` / `EVERY|15` /
|
|
17182
17218
|
* `ONCE|2026-12-31T23:00`…):一头从 `/Query /XML` 算(`specFromXml`),
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { join, dirname, resolve, relative, isAbsolute, sep, extname, basename }
|
|
|
4
4
|
import { execFile, execSync, execFileSync, spawn } from 'child_process';
|
|
5
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';
|
|
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
|
-
import { PROVIDER_TYPES, OPERATION_TYPES as OPERATION_TYPES$1, COMPLIANCE_CATEGORIES, COMPLIANCE_ACTIONS, SEARCH_PROVIDER_TYPES, CURRENCIES, LANGS, 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';
|
|
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';
|
|
9
9
|
import { createRequire } from 'module';
|
|
10
10
|
import { randomUUID, createHash, randomBytes } from 'crypto';
|
|
@@ -34,7 +34,8 @@ __export(schtasks_exports, {
|
|
|
34
34
|
quoteTaskRun: () => quoteTaskRun,
|
|
35
35
|
scheduleArgs: () => scheduleArgs,
|
|
36
36
|
specFromTrigger: () => specFromTrigger,
|
|
37
|
-
specFromXml: () => specFromXml
|
|
37
|
+
specFromXml: () => specFromXml,
|
|
38
|
+
taskRunArgv: () => taskRunArgv
|
|
38
39
|
});
|
|
39
40
|
function createSchtasksBackend(opts = {}) {
|
|
40
41
|
const run = opts.run ?? runCommand2;
|
|
@@ -99,9 +100,11 @@ function createSchtasksBackend(opts = {}) {
|
|
|
99
100
|
async inspect(osTaskId) {
|
|
100
101
|
const res = await run("schtasks", ["/Query", "/TN", osTaskId, "/XML"]);
|
|
101
102
|
if (res.code !== 0) return null;
|
|
103
|
+
const commandLine = commandLineFromXml(res.stdout);
|
|
102
104
|
return {
|
|
103
105
|
osTaskId,
|
|
104
|
-
commandLine
|
|
106
|
+
commandLine,
|
|
107
|
+
argv: taskRunArgv(commandLine),
|
|
105
108
|
spec: specFromXml(res.stdout),
|
|
106
109
|
enabled: !/<Enabled>\s*false\s*<\/Enabled>/i.test(res.stdout)
|
|
107
110
|
};
|
|
@@ -118,6 +121,13 @@ function createSchtasksBackend(opts = {}) {
|
|
|
118
121
|
function quoteTaskRun(argv) {
|
|
119
122
|
return argv.map((part) => `"${part.replace(/"/g, "")}"`).join(" ");
|
|
120
123
|
}
|
|
124
|
+
function taskRunArgv(commandLine) {
|
|
125
|
+
const out = [];
|
|
126
|
+
const re = /"([^"]*)"|(\S+)/g;
|
|
127
|
+
let m;
|
|
128
|
+
while ((m = re.exec(commandLine)) !== null) out.push(m[1] ?? m[2] ?? "");
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
121
131
|
function scheduleArgs(trigger) {
|
|
122
132
|
if (trigger.kind === "interval") {
|
|
123
133
|
const slots = intervalSlots(trigger.everyMinutes);
|
|
@@ -331,9 +341,11 @@ function createLaunchdBackend(opts = {}) {
|
|
|
331
341
|
return null;
|
|
332
342
|
}
|
|
333
343
|
const disabled = await isDisabled(run, label);
|
|
344
|
+
const argv = extractProgramArguments(xml2);
|
|
334
345
|
return {
|
|
335
346
|
osTaskId: label,
|
|
336
|
-
commandLine:
|
|
347
|
+
commandLine: argv.join(" "),
|
|
348
|
+
argv,
|
|
337
349
|
spec: extractCalendarSpec(xml2),
|
|
338
350
|
enabled: !disabled
|
|
339
351
|
};
|
|
@@ -12421,8 +12433,48 @@ var EpochConfigSchema = z.object({
|
|
|
12421
12433
|
message: "blankCards: id must be unique"
|
|
12422
12434
|
}).optional(),
|
|
12423
12435
|
blankGreeting: BlankGreetingSchema.optional(),
|
|
12424
|
-
user: HostUserSchema.optional()
|
|
12436
|
+
user: HostUserSchema.optional(),
|
|
12437
|
+
settingsHidden: z.array(z.string().min(1)).min(1).optional(),
|
|
12438
|
+
settingsPanes: z.array(
|
|
12439
|
+
z.object({
|
|
12440
|
+
id: z.string().min(1).refine((id) => !isSettingsPaneId(id), {
|
|
12441
|
+
message: `id must not collide with a built-in pane (${SETTINGS_PANE_IDS.join(", ")})`
|
|
12442
|
+
}),
|
|
12443
|
+
label: z.string().min(1),
|
|
12444
|
+
icon: z.string().min(1).optional(),
|
|
12445
|
+
url: z.string().min(1).refine(
|
|
12446
|
+
(url) => {
|
|
12447
|
+
try {
|
|
12448
|
+
const scheme = new URL(url).protocol;
|
|
12449
|
+
return scheme === "http:" || scheme === "https:";
|
|
12450
|
+
} catch {
|
|
12451
|
+
return false;
|
|
12452
|
+
}
|
|
12453
|
+
},
|
|
12454
|
+
{ message: "url must be an absolute http(s) URL" }
|
|
12455
|
+
),
|
|
12456
|
+
before: z.string().min(1).optional()
|
|
12457
|
+
})
|
|
12458
|
+
).min(1).refine((items) => new Set(items.map((item) => item.id)).size === items.length, {
|
|
12459
|
+
message: "settingsPanes: id must be unique"
|
|
12460
|
+
}).optional()
|
|
12425
12461
|
});
|
|
12462
|
+
function settingsHiddenIssues(config) {
|
|
12463
|
+
const hidden = config.settingsHidden;
|
|
12464
|
+
if (hidden === void 0) return [];
|
|
12465
|
+
return hidden.filter((id) => !isSettingsPaneId(id)).map((id) => ({
|
|
12466
|
+
path: "settingsHidden",
|
|
12467
|
+
message: `unknown settings pane id: ${id} (known: ${SETTINGS_PANE_IDS.join(", ")})`
|
|
12468
|
+
}));
|
|
12469
|
+
}
|
|
12470
|
+
function settingsPaneBeforeIssues(config) {
|
|
12471
|
+
const panes = config.settingsPanes;
|
|
12472
|
+
if (panes === void 0) return [];
|
|
12473
|
+
return panes.filter((pane) => pane.before !== void 0 && !isSettingsPaneId(pane.before)).map((pane) => ({
|
|
12474
|
+
path: `settingsPanes.${pane.id}.before`,
|
|
12475
|
+
message: `unknown settings pane id: ${String(pane.before)} (known: ${SETTINGS_PANE_IDS.join(", ")})`
|
|
12476
|
+
}));
|
|
12477
|
+
}
|
|
12426
12478
|
function defaultConfig() {
|
|
12427
12479
|
return EpochConfigSchema.parse({});
|
|
12428
12480
|
}
|
|
@@ -12893,6 +12945,8 @@ function parseRawConfig(raw, issues, track) {
|
|
|
12893
12945
|
EpochConfigSchema.parse({})
|
|
12894
12946
|
);
|
|
12895
12947
|
issues.push(...outcome.issues);
|
|
12948
|
+
issues.push(...settingsHiddenIssues(outcome.value));
|
|
12949
|
+
issues.push(...settingsPaneBeforeIssues(outcome.value));
|
|
12896
12950
|
if (outcome.issues.length === 0) collectKeyPaths(migrated.raw, track.file);
|
|
12897
12951
|
return outcome.value;
|
|
12898
12952
|
}
|
|
@@ -19524,6 +19578,9 @@ var ScheduleRegistrar = class {
|
|
|
19524
19578
|
this.opts = opts;
|
|
19525
19579
|
}
|
|
19526
19580
|
opts;
|
|
19581
|
+
get homeDir() {
|
|
19582
|
+
return this.opts.homeDir;
|
|
19583
|
+
}
|
|
19527
19584
|
osTaskIdFor(taskId) {
|
|
19528
19585
|
const backend = this.opts.backend;
|
|
19529
19586
|
if (!backend) return "";
|
|
@@ -19594,7 +19651,6 @@ var ScheduleRegistrar = class {
|
|
|
19594
19651
|
if (this.opts.backend && def.osTaskId) await this.opts.backend.retire(def.osTaskId);
|
|
19595
19652
|
}
|
|
19596
19653
|
};
|
|
19597
|
-
// src/schedule/doctor.ts
|
|
19598
19654
|
async function diagnoseSchedules(opts) {
|
|
19599
19655
|
const { store, backend, registrar } = opts;
|
|
19600
19656
|
if (!backend) return { checked: 0, drifts: [], unsupported: true };
|
|
@@ -19631,8 +19687,18 @@ async function diagnoseSchedules(opts) {
|
|
|
19631
19687
|
});
|
|
19632
19688
|
}
|
|
19633
19689
|
}
|
|
19690
|
+
let foreign = 0;
|
|
19634
19691
|
for (const osTaskId of osTaskIds) {
|
|
19635
19692
|
if (seen.has(osTaskId)) continue;
|
|
19693
|
+
const snapshot = await backend.inspect(osTaskId);
|
|
19694
|
+
if (!snapshot) {
|
|
19695
|
+
foreign++;
|
|
19696
|
+
continue;
|
|
19697
|
+
}
|
|
19698
|
+
if (!ownedByThisHome(snapshot.argv, registrar.homeDir)) {
|
|
19699
|
+
foreign++;
|
|
19700
|
+
continue;
|
|
19701
|
+
}
|
|
19636
19702
|
const taskId = backend.taskIdFrom(osTaskId);
|
|
19637
19703
|
drifts.push({
|
|
19638
19704
|
kind: "orphan-in-os",
|
|
@@ -19640,7 +19706,17 @@ async function diagnoseSchedules(opts) {
|
|
|
19640
19706
|
...taskId ? { scheduleId: taskId } : {}
|
|
19641
19707
|
});
|
|
19642
19708
|
}
|
|
19643
|
-
return {
|
|
19709
|
+
return {
|
|
19710
|
+
checked: defs.length + osTaskIds.length - seen.size - foreign,
|
|
19711
|
+
drifts,
|
|
19712
|
+
unsupported: false
|
|
19713
|
+
};
|
|
19714
|
+
}
|
|
19715
|
+
function ownedByThisHome(argv, homeDir) {
|
|
19716
|
+
const at = argv.indexOf("--home");
|
|
19717
|
+
const home = at >= 0 ? argv[at + 1] : void 0;
|
|
19718
|
+
if (home === void 0 || home.length === 0) return true;
|
|
19719
|
+
return samePath(home, homeDir);
|
|
19644
19720
|
}
|
|
19645
19721
|
function compare2(def, snapshot, backend, registrar) {
|
|
19646
19722
|
const expected = backend.expectedSnapshot(registrar.toRegisterInput(def, def.osCommand));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epoch-agent/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "epoch-agent 核心引擎:ReAct 循环、Provider 路由、工具调度、记忆管理",
|
|
6
6
|
"repository": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"gpt-tokenizer": "^3.4.0",
|
|
28
28
|
"js-yaml": "^5.2.3",
|
|
29
29
|
"zod": "^4.4.3",
|
|
30
|
-
"@epoch-agent/infra": "0.
|
|
31
|
-
"@epoch-agent/protocol": "0.
|
|
30
|
+
"@epoch-agent/infra": "0.16.0",
|
|
31
|
+
"@epoch-agent/protocol": "0.16.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@ai-sdk/amazon-bedrock": "^5.0.40",
|