@sema-agent/server 7.98.0 → 7.100.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/MIGRATION.md +19 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +86 -60
- package/deploy/sema-up/lib/envf.sh +110 -42
- package/deploy/sema-up/sema-up.sh +76 -34
- package/dist/approval-ask-machine.d.ts +10 -0
- package/dist/approval-ask-machine.js +3 -0
- package/dist/approval-card.d.ts +74 -1
- package/dist/approval-card.js +41 -8
- package/dist/approval.d.ts +44 -20
- package/dist/approval.js +14 -6
- package/dist/boot/config-center.d.ts +16 -8
- package/dist/boot/config-center.js +206 -103
- package/dist/boot/execution-env.d.ts +1 -2
- package/dist/boot/execution-env.js +2 -2
- package/dist/boot/leader.js +12 -9
- package/dist/boot/memory-consolidation.d.ts +38 -0
- package/dist/boot/memory-consolidation.js +35 -0
- package/dist/boot/org-memory.d.ts +2 -1
- package/dist/boot/org-memory.js +9 -5
- package/dist/boot/resolve-spec.d.ts +0 -1
- package/dist/boot/resolve-spec.js +4 -3
- package/dist/boot/runner-deps.d.ts +2 -2
- package/dist/boot/runtime-caps.js +4 -4
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-06-runners.d.ts +2 -2
- package/dist/boot/stage-06-runners.js +3 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -3
- package/dist/boot/stage-07-capability-layer.js +6 -6
- package/dist/boot/stage-08-reapers.d.ts +3 -4
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +2 -3
- package/dist/boot/stage-10-http-server.d.ts +2 -3
- package/dist/boot/stage-10-http-server.js +2 -2
- package/dist/capabilities/center-plugins.d.ts +14 -2
- package/dist/capabilities/center-plugins.js +13 -5
- package/dist/capabilities/center-prompts.d.ts +3 -0
- package/dist/capabilities/center-prompts.js +1 -1
- package/dist/capabilities/hands-lane.js +2 -1
- package/dist/capabilities/scenarios.js +18 -5
- package/dist/capabilities/tool-defer.d.ts +2 -2
- package/dist/center-credential.d.ts +112 -0
- package/dist/center-credential.js +131 -0
- package/dist/config-catalog.d.ts +2 -2
- package/dist/config-catalog.js +15 -15
- package/dist/config-center/apply-effective.d.ts +34 -39
- package/dist/config-center/apply-effective.js +100 -64
- package/dist/config-center/apply-ledger.d.ts +35 -16
- package/dist/config-center/apply-ledger.js +25 -18
- package/dist/config-center/center-request.d.ts +60 -0
- package/dist/config-center/center-request.js +71 -0
- package/dist/config-center/facade.d.ts +11 -5
- package/dist/config-center/facade.js +1 -1
- package/dist/config-center/hot-keys-registry.d.ts +11 -4
- package/dist/config-center/hot-keys-registry.js +11 -7
- package/dist/config-center/http-client.d.ts +17 -9
- package/dist/config-center/http-client.js +27 -36
- package/dist/config-center/restart-signal.d.ts +21 -14
- package/dist/config-center/restart-signal.js +16 -22
- package/dist/config-center/skills-mcp.d.ts +4 -1
- package/dist/config-center/skills-mcp.js +2 -2
- package/dist/config-center/types.d.ts +3 -3
- package/dist/config-invariants.d.ts +2 -2
- package/dist/config-invariants.js +0 -8
- package/dist/config-lkg.d.ts +47 -8
- package/dist/config-lkg.js +107 -20
- package/dist/config-provider.d.ts +8 -7
- package/dist/config-provider.js +5 -5
- package/dist/config-types.d.ts +30 -11
- package/dist/config.js +11 -13
- package/dist/cross-session-settings.js +1 -1
- package/dist/fleet-client.d.ts +8 -8
- package/dist/fleet-client.js +7 -7
- package/dist/fleet-lease.d.ts +11 -11
- package/dist/fleet-lease.js +17 -13
- package/dist/host-lsp-manager.d.ts +29 -0
- package/dist/host-lsp-manager.js +14 -0
- package/dist/hosted-posture.d.ts +49 -93
- package/dist/hosted-posture.js +1 -25
- package/dist/http/active-run-conflict.d.ts +2 -12
- package/dist/http/active-run-conflict.js +1 -6
- package/dist/http/admission.js +8 -0
- package/dist/http/resume-legs.d.ts +1 -1
- package/dist/http/resume-legs.js +14 -10
- package/dist/http/route-ctx.d.ts +2 -2
- package/dist/http/routes/approvals-assistant.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.js +2 -2
- package/dist/http/routes/memory-compliance.js +5 -0
- package/dist/http/routes/memory-origin.js +5 -0
- package/dist/http/routes/sessions.js +6 -0
- package/dist/http/routes/tasks.js +7 -6
- package/dist/http/server.d.ts +6 -5
- package/dist/http/wire-types.d.ts +6 -3
- package/dist/leader/wire.d.ts +20 -12
- package/dist/leader/wire.js +7 -6
- package/dist/memory-layer-preflight.d.ts +46 -0
- package/dist/memory-layer-preflight.js +121 -0
- package/dist/memory-operator-faces.js +17 -1
- package/dist/observability/corrupt-read-seat.d.ts +21 -4
- package/dist/observability/corrupt-read-seat.js +31 -0
- package/dist/observability/fail-open.d.ts +8 -4
- package/dist/observability/fail-open.js +8 -4
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +3 -26
- package/dist/observability/secret-env-scrub.js +3 -2
- package/dist/orchestration/workflow-completion-inbox.d.ts +31 -23
- package/dist/orchestration/workflow-completion-inbox.js +8 -3
- package/dist/plugins/approval-ask-store-file.d.ts +20 -2
- package/dist/plugins/approval-ask-store-file.js +21 -3
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -0
- package/dist/plugins/approval-ask-store-memory.js +39 -13
- package/dist/plugins/approval-ask-store-sql.d.ts +24 -5
- package/dist/plugins/approval-ask-store-sql.js +27 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +9 -3
- package/dist/plugins/checkpoint-store-sql.js +19 -2
- package/dist/plugins/local-checkpoint-store.js +2 -0
- package/dist/plugins/mailbox-store-sql.d.ts +7 -5
- package/dist/plugins/mailbox-store-sql.js +6 -4
- package/dist/plugins/permission-rule-store-file.js +3 -2
- package/dist/plugins/remote-env-host.d.ts +3 -1
- package/dist/plugins/remote-env-host.js +3 -2
- package/dist/plugins/sql-json-column.d.ts +16 -3
- package/dist/plugins/sql-json-column.js +15 -4
- package/dist/plugins/web-search.d.ts +42 -22
- package/dist/plugins/web-search.js +141 -49
- package/dist/project-memory.d.ts +28 -1
- package/dist/project-memory.js +22 -22
- package/dist/run-local.js +6 -7
- package/dist/runs.js +6 -5
- package/dist/runtime-caps-resolver.d.ts +8 -8
- package/dist/runtime-caps-resolver.js +16 -14
- package/dist/runtime-governance.d.ts +50 -3
- package/dist/runtime-governance.js +5 -0
- package/dist/sealed-key.js +3 -7
- package/dist/server-secret-env.d.ts +43 -0
- package/dist/server-secret-env.js +18 -0
- package/dist/task-settings.d.ts +1 -1
- package/dist/tool-approval.d.ts +144 -9
- package/dist/tool-approval.js +74 -18
- package/dist/trace/core-keyset-guard.d.ts +5 -5
- package/dist/trace/ledger-sink.js +2 -2
- package/dist/trace/project.d.ts +13 -0
- package/dist/trace/project.js +22 -5
- package/dist/trace/projection-drop.d.ts +2 -0
- package/dist/trace/projection-drop.js +6 -0
- package/dist/trace/sema-provenance.d.ts +4 -1
- package/dist/trace/sema-provenance.js +1 -1
- package/dist/trace/task-notification-facets.d.ts +65 -0
- package/dist/trace/task-notification-facets.js +31 -0
- package/dist/trace/wire-projection-faces.d.ts +3 -3
- package/dist/trace/wire-projection-faces.js +3 -3
- package/package.json +5 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type EffectiveReadWarning, type EntitlementRuntimeCaps } from "@sema-agent/settings-schema";
|
|
2
2
|
import type { ScenarioRuling } from "../capabilities/scenarios.js";
|
|
3
3
|
import type { EffectiveConfig, ExecutionRuling } from "./types.js";
|
|
4
|
+
import { type CenterEndpoint } from "./center-request.js";
|
|
4
5
|
/** GET the effective config (Bearer + ETag). null = 304 (unchanged). Throws on transport/HTTP error, and on a
|
|
5
6
|
* payload that is not an effective config at all(非对象 / version 非有限数 / gate 域坏形——[ref] 裁B)。
|
|
6
7
|
* `domainErrors`:坏 catalog 域(schema default 已落)逐域单列——与本地腿 `FetchEffectiveResult` 同键同义,
|
|
@@ -12,8 +13,11 @@ import type { EffectiveConfig, ExecutionRuling } from "./types.js";
|
|
|
12
13
|
* `legacy-governance-lifted` 铸出来,理由逐字写在 `legacyGovernanceFromRuntime` 的 SUNSET 注里:
|
|
13
14
|
* 「关窗的前提是有人知道它还开着」。两条读腿各返一份原流,那句话在本仓才成立。
|
|
14
15
|
* 🔐 原流的 `error` 字段**未经** `redactConfigError`(那道脱敏挂在真正进日志流的 `domainErrors` 产出边界上)
|
|
15
|
-
* —— 任何把本键路由进结构化日志/审计流的消费者必须自己先脱敏。
|
|
16
|
-
|
|
16
|
+
* —— 任何把本键路由进结构化日志/审计流的消费者必须自己先脱敏。
|
|
17
|
+
*
|
|
18
|
+
* `credentialIdentity`(S-651 / [ref] E-15):这次拉取所用凭证的身份(`center-credential.ts`)。调用方拿它给
|
|
19
|
+
* 候选打分箱标记 —— LKG / prompt 活动状态只许落进**拉到它的那个身份**的箱。 */
|
|
20
|
+
export declare function fetchEffective(center: CenterEndpoint, etag: string | undefined, fetchImpl?: typeof fetch, worker?: string): Promise<{
|
|
17
21
|
effective: EffectiveConfig;
|
|
18
22
|
etag?: string;
|
|
19
23
|
domainErrors?: Array<{
|
|
@@ -21,6 +25,7 @@ export declare function fetchEffective(baseUrl: string, token: string, etag: str
|
|
|
21
25
|
error: string;
|
|
22
26
|
}>;
|
|
23
27
|
readWarnings: readonly EffectiveReadWarning[];
|
|
28
|
+
credentialIdentity: string;
|
|
24
29
|
} | null>;
|
|
25
30
|
/**
|
|
26
31
|
* [ref] §K (core 1.157 `RunnerDeps.runtimeCapsResolver`) — GET the PER-PRINCIPAL runtime
|
|
@@ -41,7 +46,7 @@ export declare function fetchEffective(baseUrl: string, token: string, etag: str
|
|
|
41
46
|
* fail-closes (core then DENIES the optional `allowWorkflows` cap — an outage must never silently GRANT). ETag is
|
|
42
47
|
* content-hashed (`p-<hash>`); an `if-none-match` poll is cheap. Mirrors `fetchEffective` (Bearer + 8s + scheme guard).
|
|
43
48
|
*/
|
|
44
|
-
export declare function fetchPrincipalCaps(
|
|
49
|
+
export declare function fetchPrincipalCaps(center: CenterEndpoint, principal: string, etag: string | undefined, fetchImpl?: typeof fetch, worker?: string): Promise<{
|
|
45
50
|
runtimeCaps: EntitlementRuntimeCaps | null;
|
|
46
51
|
configured: boolean;
|
|
47
52
|
scenario?: ScenarioRuling;
|
|
@@ -68,7 +73,7 @@ export declare function fetchPrincipalCaps(baseUrl: string, token: string, princ
|
|
|
68
73
|
* 段在场 ⇒ 原值(空表 = 取数成功的负结果,与缺席不同格)。条件请求不适用(本腿恒不带 etag),
|
|
69
74
|
* 因此 304 在传输层就是 fail-loud。
|
|
70
75
|
*/
|
|
71
|
-
export declare function fetchPrincipalOrgMemory(
|
|
76
|
+
export declare function fetchPrincipalOrgMemory(center: CenterEndpoint, principal: string, fetchImpl?: typeof fetch, worker?: string): Promise<unknown>;
|
|
72
77
|
/** An HTTP error from a config-center fetch that carries the response status so callers can branch on it
|
|
73
78
|
* (e.g. translate a 404 to "unknown hash → undefined") WITHOUT parsing the message string. */
|
|
74
79
|
export declare class ConfigCenterHttpError extends Error {
|
|
@@ -76,18 +81,21 @@ export declare class ConfigCenterHttpError extends Error {
|
|
|
76
81
|
constructor(message: string, status: number);
|
|
77
82
|
}
|
|
78
83
|
/**
|
|
79
|
-
* Fetch one skill's body by content hash (`GET
|
|
84
|
+
* Fetch one skill's body by content hash (`GET <content root>/skills/content/<hash>`, Bearer; the root is
|
|
85
|
+
* `/api/v1/me` for a user-JWT credential and `/api/config` otherwise — center-request.ts) and VERIFY its
|
|
80
86
|
* sha256 matches the manifest hash (integrity + rewrite check). The content is immutable per hash, so the
|
|
81
87
|
* caller caches by hash and never re-fetches an unchanged skill. Throws a {@link ConfigCenterHttpError}
|
|
82
88
|
* (carrying `.status`) on an HTTP error — INCLUDING 404 — or a plain Error on hash mismatch. Callers that
|
|
83
89
|
* want "unknown hash → undefined" parity with the local backend inspect `.status === 404` and swallow it;
|
|
84
90
|
* the legacy `applyCenterSkills` path keeps treating every throw as "skip this skill, keep baseline".
|
|
85
91
|
*/
|
|
86
|
-
export declare function fetchSkillContent(
|
|
92
|
+
export declare function fetchSkillContent(center: CenterEndpoint, contentHash: string, fetchImpl?: typeof fetch): Promise<string>;
|
|
87
93
|
/** [ref]b / [ref]① — §9.4 by-digest 补拉二函(fetchSkillContent 同姿势:HTTP+Bearer+8s 超时+
|
|
88
94
|
* 消费侧自证)。artifact=envelope JSON(验真=调用方过 core verifyPromptArtifact,canonical 重算——
|
|
89
95
|
* 本函数只做传输与形读,不超范围解释);blob=段文本 raw-byte(sha256 逐位自证,fetchSkillContent 同款)。
|
|
90
|
-
* digest 参数收带前缀/裸 hex 两形([ref] 参数口径)。
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
* digest 参数收带前缀/裸 hex 两形([ref] 参数口径)。路径根按凭证种类(B-5,center-request.ts)。
|
|
97
|
+
* ⚠️ 现状(S-651 取证车MS 总表第 8 条):`fetchPromptBlob` 在 `src/` 里**没有生产调用点**,真走得到的内容
|
|
98
|
+
* 拉取只有 skill 正文与 prompt 产物两条;它与另两条共用同一张路由表,本批不为它新接线。 */
|
|
99
|
+
export declare function fetchPromptArtifact(center: CenterEndpoint, artifactDigest: string, fetchImpl?: typeof fetch): Promise<unknown>;
|
|
100
|
+
export declare function fetchPromptBlob(center: CenterEndpoint, contentDigest: string, fetchImpl?: typeof fetch): Promise<string>;
|
|
93
101
|
//# sourceMappingURL=http-client.d.ts.map
|
|
@@ -2,15 +2,11 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { readEffectiveWire, PrincipalCapsWire } from "@sema-agent/settings-schema";
|
|
3
3
|
import { centerPromptsFromEffective } from "../prompts-domain-validate.js";
|
|
4
4
|
import { foldEffectiveReadWarning } from "./read-warnings.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const res = await fetchImpl(url, {
|
|
11
|
-
headers: { authorization: `Bearer ${token}`, ...(etag ? { "if-none-match": etag } : {}) },
|
|
12
|
-
signal: AbortSignal.timeout(8000),
|
|
13
|
-
});
|
|
5
|
+
import { centerFetch } from "./center-request.js";
|
|
6
|
+
import { answerStillCurrent } from "../center-credential.js";
|
|
7
|
+
const CENTER_PULL_TIMEOUT_MS = 8000;
|
|
8
|
+
export async function fetchEffective(center, etag, fetchImpl = fetch, worker) {
|
|
9
|
+
const { res, identity } = await centerFetch(center, { kind: "effective", worker }, { etag, timeoutMs: CENTER_PULL_TIMEOUT_MS, fetchImpl });
|
|
14
10
|
if (res.status === 304)
|
|
15
11
|
return null;
|
|
16
12
|
if (!res.ok)
|
|
@@ -29,10 +25,10 @@ export async function fetchEffective(baseUrl, token, etag, fetchImpl = fetch, wo
|
|
|
29
25
|
domainErrors.push(f);
|
|
30
26
|
}
|
|
31
27
|
const effective = wire;
|
|
32
|
-
return { effective, etag: res.headers.get("etag") ?? undefined, readWarnings: warnings, ...(domainErrors.length > 0 ? { domainErrors } : {}) };
|
|
28
|
+
return { effective, etag: res.headers.get("etag") ?? undefined, readWarnings: warnings, credentialIdentity: identity, ...(domainErrors.length > 0 ? { domainErrors } : {}) };
|
|
33
29
|
}
|
|
34
|
-
export async function fetchPrincipalCaps(
|
|
35
|
-
const raw = await requestPrincipalView(
|
|
30
|
+
export async function fetchPrincipalCaps(center, principal, etag, fetchImpl = fetch, worker) {
|
|
31
|
+
const raw = await requestPrincipalView(center, principal, etag, fetchImpl, worker);
|
|
36
32
|
if (raw === null)
|
|
37
33
|
return null;
|
|
38
34
|
const parsedBody = PrincipalCapsWire.safeParse(raw.json);
|
|
@@ -84,31 +80,29 @@ function assertPrincipalEcho(echoed, principal) {
|
|
|
84
80
|
throw new Error(`config-center principal-caps response echoes principal ${JSON.stringify(echoed)} but ${JSON.stringify(principal)} was requested — discarding the whole response`);
|
|
85
81
|
}
|
|
86
82
|
}
|
|
87
|
-
async function requestPrincipalView(
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const url = `${baseUrl.replace(/\/+$/, "")}/api/config/effective?${params.toString()}`;
|
|
95
|
-
const res = await fetchImpl(url, {
|
|
96
|
-
headers: { authorization: `Bearer ${token}`, ...(etag ? { "if-none-match": etag } : {}) },
|
|
97
|
-
signal: AbortSignal.timeout(8000),
|
|
98
|
-
});
|
|
83
|
+
async function requestPrincipalView(center, principal, etag, fetchImpl, worker) {
|
|
84
|
+
const { res, identity } = await centerFetch(center, { kind: "effective", principal, worker }, { etag, timeoutMs: CENTER_PULL_TIMEOUT_MS, fetchImpl });
|
|
85
|
+
const stillCurrent = () => {
|
|
86
|
+
if (!answerStillCurrent(center.credential, identity)) {
|
|
87
|
+
throw new Error("center credential identity changed while the principal view was in flight — response discarded; the next lookup runs under the current credential");
|
|
88
|
+
}
|
|
89
|
+
};
|
|
99
90
|
if (res.status === 304) {
|
|
100
91
|
if (!etag)
|
|
101
92
|
throw new Error("config-center returned 304 to a non-conditional principal-caps request");
|
|
93
|
+
stillCurrent();
|
|
102
94
|
return null;
|
|
103
95
|
}
|
|
104
96
|
if (!res.ok)
|
|
105
97
|
throw new Error(`config-center principal-caps HTTP ${res.status}`);
|
|
106
98
|
const responseEtag = res.headers.get("etag");
|
|
107
|
-
|
|
99
|
+
const json = await res.json();
|
|
100
|
+
stillCurrent();
|
|
101
|
+
return { json, ...(responseEtag !== null ? { etag: responseEtag } : {}) };
|
|
108
102
|
}
|
|
109
103
|
const PrincipalOrgMemoryEnvelope = PrincipalCapsWire.pick({ principal: true, orgMemory: true });
|
|
110
|
-
export async function fetchPrincipalOrgMemory(
|
|
111
|
-
const raw = await requestPrincipalView(
|
|
104
|
+
export async function fetchPrincipalOrgMemory(center, principal, fetchImpl = fetch, worker) {
|
|
105
|
+
const raw = await requestPrincipalView(center, principal, undefined, fetchImpl, worker);
|
|
112
106
|
if (raw === null)
|
|
113
107
|
throw new Error("config-center returned 304 to a non-conditional org-directory fetch");
|
|
114
108
|
const parsed = PrincipalOrgMemoryEnvelope.safeParse(raw.json);
|
|
@@ -126,9 +120,8 @@ export class ConfigCenterHttpError extends Error {
|
|
|
126
120
|
this.name = "ConfigCenterHttpError";
|
|
127
121
|
}
|
|
128
122
|
}
|
|
129
|
-
export async function fetchSkillContent(
|
|
130
|
-
const
|
|
131
|
-
const res = await fetchImpl(url, { headers: { authorization: `Bearer ${token}` }, signal: AbortSignal.timeout(8000) });
|
|
123
|
+
export async function fetchSkillContent(center, contentHash, fetchImpl = fetch) {
|
|
124
|
+
const { res } = await centerFetch(center, { kind: "skill-content", contentHash }, { timeoutMs: CENTER_PULL_TIMEOUT_MS, fetchImpl });
|
|
132
125
|
if (!res.ok)
|
|
133
126
|
throw new ConfigCenterHttpError(`skill content HTTP ${res.status} for ${contentHash}`, res.status);
|
|
134
127
|
const content = await res.text();
|
|
@@ -138,16 +131,14 @@ export async function fetchSkillContent(baseUrl, token, contentHash, fetchImpl =
|
|
|
138
131
|
throw new Error(`skill content hash mismatch for ${contentHash}: computed sha256:${got}`);
|
|
139
132
|
return content;
|
|
140
133
|
}
|
|
141
|
-
export async function fetchPromptArtifact(
|
|
142
|
-
const
|
|
143
|
-
const res = await fetchImpl(url, { headers: { authorization: `Bearer ${token}` }, signal: AbortSignal.timeout(8000) });
|
|
134
|
+
export async function fetchPromptArtifact(center, artifactDigest, fetchImpl = fetch) {
|
|
135
|
+
const { res } = await centerFetch(center, { kind: "prompt-artifact", digest: artifactDigest }, { timeoutMs: CENTER_PULL_TIMEOUT_MS, fetchImpl });
|
|
144
136
|
if (!res.ok)
|
|
145
137
|
throw new ConfigCenterHttpError(`prompt artifact HTTP ${res.status} for ${artifactDigest}`, res.status);
|
|
146
138
|
return await res.json();
|
|
147
139
|
}
|
|
148
|
-
export async function fetchPromptBlob(
|
|
149
|
-
const
|
|
150
|
-
const res = await fetchImpl(url, { headers: { authorization: `Bearer ${token}` }, signal: AbortSignal.timeout(8000) });
|
|
140
|
+
export async function fetchPromptBlob(center, contentDigest, fetchImpl = fetch) {
|
|
141
|
+
const { res } = await centerFetch(center, { kind: "prompt-blob", digest: contentDigest }, { timeoutMs: CENTER_PULL_TIMEOUT_MS, fetchImpl });
|
|
151
142
|
if (!res.ok)
|
|
152
143
|
throw new ConfigCenterHttpError(`prompt blob HTTP ${res.status} for ${contentDigest}`, res.status);
|
|
153
144
|
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EffectiveConfig } from "./types.js";
|
|
2
|
-
export type RestartSlice = "skills" | "mcp" | "a2a" | "scenarios" | "
|
|
2
|
+
export type RestartSlice = "skills" | "mcp" | "a2a" | "scenarios" | "degrade-route" | "read-face" | "memory-consolidation";
|
|
3
3
|
/** What the CALLER must contribute about boot-baked catalog consumers that live OUTSIDE the Runner — the
|
|
4
4
|
* slices cannot see them, because they are configured from env (`ServiceConfig`), not from the center's
|
|
5
5
|
* EffectiveConfig. Absent/empty = that lane is off ⇒ its slice is inert (null on both sides). */
|
|
@@ -18,6 +18,18 @@ export interface RestartSliceCtx {
|
|
|
18
18
|
* 新增/改址/域整体出现或消失仍签(新 mount / 改址只能 restart 才生效)。缺席/false = 旧语义照签
|
|
19
19
|
* (fail-closed:没接席的部署里删除向没人承接,restart 是它唯一的生效路径)。 */
|
|
20
20
|
mcpRevocationLive?: boolean;
|
|
21
|
+
/** S-668 波 0(过渡;**波 1 转热后删**):记忆整理驱动席的两侧读数 —— `baked` = boot 期 core 解析器选中的
|
|
22
|
+
* 那只 Model 的指纹,`current` = 同一只解析器对本拍活配置再解一次的指纹(读法见
|
|
23
|
+
* boot/memory-consolidation.ts `createConsolidationSeatWatch`)。缺席 = 阀门关着(`MEMORY_CONSOLIDATION_DRIVER`
|
|
24
|
+
* 不是 on,或记忆引擎没接线)⇒ 没有 boot 烤死的席 ⇒ `memory-consolidation` 片恒不签。 */
|
|
25
|
+
consolidationSeat?: {
|
|
26
|
+
readonly baked: unknown;
|
|
27
|
+
readonly current: unknown;
|
|
28
|
+
};
|
|
29
|
+
/** S-668 波 0(codex r1 [medium]):插件 host 白名单(env `PLUGINS_ALLOW_HOSTS`,boot 常量)—— 白名单外的声明
|
|
30
|
+
* 装载器整条跳过,它们的变化不是重启理由。生产 `restartCtx` 恒传 `config.pluginsAllowHosts`;缺席(单元调用)
|
|
31
|
+
* = 装载器的出厂名单 `DEFAULT_PLUGIN_ALLOW_HOSTS`。 */
|
|
32
|
+
pluginsAllowHosts?: readonly string[];
|
|
21
33
|
}
|
|
22
34
|
/** Structured restart signal an orchestrator consumes (GET /health → `restart`). Change-detected against the
|
|
23
35
|
* process's BOOT config, NOT presence — so it stays absent when nothing baked-at-boot changed (presence would
|
|
@@ -46,18 +58,13 @@ export declare function stableStringify(v: unknown): string;
|
|
|
46
58
|
* can auto rolling-restart on a non-empty result WITHOUT a restart loop, because the comparison is always
|
|
47
59
|
* against boot (a refresh that re-fires the same diff is idempotent, not a fresh trigger). */
|
|
48
60
|
export declare function restartReasons(boot: EffectiveConfig | undefined, current: EffectiveConfig, ctx?: RestartSliceCtx): RestartSlice[];
|
|
49
|
-
/**
|
|
50
|
-
* default) of `next` differs from the last
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
/** codex R12: TRUE when this candidate resolves an ACTIVE tier table. Used by main.ts's defer predicate — a
|
|
58
|
-
* tier-less-booted Runner never re-runs expandTiers, so hot-applying an ARRIVING tier table splits admission
|
|
59
|
-
* (tier words pass the expanded gate) from execution (core throws "Unknown model ref"). Hot-apply of the model
|
|
60
|
-
* plane is safe only when BOTH the constructed generation and the candidate are tier-less. */
|
|
61
|
-
export declare function planeHasActiveTiers(eff: EffectiveConfig): boolean;
|
|
61
|
+
/** The refresh loop's SWAP gate: TRUE when the MODEL PLANE (enabled models + active tier table + resolved
|
|
62
|
+
* default) of `next` differs from `prev`, the last plane handed to `swapRunnerDeps` — only then does the tick
|
|
63
|
+
* pass `swapPlane` to applyEffective, so a candidate that moved only hot fields (pricing values / quota weights /
|
|
64
|
+
* the `enabled:true` spelling, see catalogEntryFingerprint) or nothing on the plane swaps nothing. `prev ===
|
|
65
|
+
* undefined` (env-boot plane, no EffectiveConfig to compare) is conservatively "changed": the first center plane
|
|
66
|
+
* always swaps. Not gated on tier activity: a Runner's expanded catalog goes stale on ANY plane change,
|
|
67
|
+
* including a tiers-off flip, and the default entry rides the fingerprint because the Runner's copy carries its
|
|
68
|
+
* own `default` (codex R8; SAME resolver as applyEffective — resolveDefaultModelName, single source). */
|
|
62
69
|
export declare function modelPlaneChanged(prev: EffectiveConfig | undefined, next: EffectiveConfig): boolean;
|
|
63
70
|
//# sourceMappingURL=restart-signal.d.ts.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { resolveActiveTiers } from "@sema-agent/settings-schema";
|
|
2
|
+
import { DEFAULT_PLUGIN_ALLOW_HOSTS, materializablePlugins } from "../capabilities/center-plugins.js";
|
|
2
3
|
import { resolveDefaultModelName } from "./apply-effective.js";
|
|
3
4
|
import { CENTER_READ_FACE_LIVE_KEYS } from "./read-face.js";
|
|
4
|
-
const RESTART_SLICES = ["skills", "mcp", "a2a", "scenarios", "
|
|
5
|
+
const RESTART_SLICES = ["skills", "mcp", "a2a", "scenarios", "degrade-route", "read-face", "memory-consolidation"];
|
|
5
6
|
export function stableStringify(v) {
|
|
6
7
|
if (v === null || typeof v !== "object")
|
|
7
8
|
return JSON.stringify(v) ?? "null";
|
|
@@ -26,31 +27,29 @@ function planeEntriesFingerprint(rows) {
|
|
|
26
27
|
const enabled = enabledOnly(rows);
|
|
27
28
|
return enabled ? enabled.map((m) => catalogEntryFingerprint(m)) : null;
|
|
28
29
|
}
|
|
30
|
+
function restartSlicePair(boot, current, slice, ctx) {
|
|
31
|
+
if (slice === "memory-consolidation") {
|
|
32
|
+
const seat = ctx?.consolidationSeat;
|
|
33
|
+
return seat === undefined ? [null, null] : [seat.baked, seat.current];
|
|
34
|
+
}
|
|
35
|
+
return [restartSliceValue(boot, slice, ctx), restartSliceValue(current, slice, ctx)];
|
|
36
|
+
}
|
|
29
37
|
function restartSliceValue(eff, slice, ctx) {
|
|
30
38
|
if (!eff)
|
|
31
39
|
return null;
|
|
32
40
|
switch (slice) {
|
|
33
|
-
case "skills":
|
|
34
|
-
|
|
41
|
+
case "skills": {
|
|
42
|
+
const skills = enabledOnly(eff.skills?.skills);
|
|
43
|
+
const materialized = materializablePlugins(eff, ctx?.pluginsAllowHosts ?? DEFAULT_PLUGIN_ALLOW_HOSTS);
|
|
44
|
+
const plugins = materialized.length > 0 ? materialized : null;
|
|
45
|
+
return skills === null && plugins === null ? null : { skills, plugins };
|
|
46
|
+
}
|
|
35
47
|
case "mcp":
|
|
36
48
|
return enabledOnly(eff.mcp?.servers);
|
|
37
49
|
case "a2a":
|
|
38
50
|
return enabledOnly(eff.a2a?.peers);
|
|
39
51
|
case "scenarios":
|
|
40
52
|
return enabledOnly(eff.scenarios?.scenarios);
|
|
41
|
-
case "runtime-gates": {
|
|
42
|
-
const ar = eff.governance?.approvalRequire;
|
|
43
|
-
return Array.isArray(ar) ? { approvalRequire: ar } : null;
|
|
44
|
-
}
|
|
45
|
-
case "models-tiers": {
|
|
46
|
-
const active = eff.models ? resolveActiveTiers(eff.models) : undefined;
|
|
47
|
-
if (!active || Object.keys(active).length === 0)
|
|
48
|
-
return null;
|
|
49
|
-
const enabled = enabledOnly(eff.models?.models);
|
|
50
|
-
const names = new Set((enabled ?? []).map((m) => m.name));
|
|
51
|
-
const def = resolveDefaultModelName(eff, (n) => names.has(n), enabled?.[0]?.name ?? "");
|
|
52
|
-
return { models: planeEntriesFingerprint(eff.models?.models), tiers: active, default: def.name };
|
|
53
|
-
}
|
|
54
53
|
case "read-face": {
|
|
55
54
|
const d = eff.readFace;
|
|
56
55
|
if (!d)
|
|
@@ -70,8 +69,7 @@ function restartSliceValue(eff, slice, ctx) {
|
|
|
70
69
|
}
|
|
71
70
|
export function restartReasons(boot, current, ctx) {
|
|
72
71
|
return RESTART_SLICES.filter((s) => {
|
|
73
|
-
const b =
|
|
74
|
-
const c = restartSliceValue(current, s, ctx);
|
|
72
|
+
const [b, c] = restartSlicePair(boot, current, s, ctx);
|
|
75
73
|
if (stableStringify(b) === stableStringify(c))
|
|
76
74
|
return false;
|
|
77
75
|
if (s === "mcp" && ctx?.mcpRevocationLive === true && Array.isArray(b) && Array.isArray(c) && c.length < b.length) {
|
|
@@ -89,10 +87,6 @@ export function restartReasons(boot, current, ctx) {
|
|
|
89
87
|
return true;
|
|
90
88
|
});
|
|
91
89
|
}
|
|
92
|
-
export function planeHasActiveTiers(eff) {
|
|
93
|
-
const active = eff.models ? resolveActiveTiers(eff.models) : undefined;
|
|
94
|
-
return active !== undefined && Object.keys(active).length > 0;
|
|
95
|
-
}
|
|
96
90
|
export function modelPlaneChanged(prev, next) {
|
|
97
91
|
if (!prev)
|
|
98
92
|
return true;
|
|
@@ -2,6 +2,7 @@ import type { A2aServerSpec, McpServerSpec } from "@sema-agent/core";
|
|
|
2
2
|
import type { CenterMcp, ScopedA2aPeer } from "../config-types.js";
|
|
3
3
|
import type { Logger } from "../observability/logger.js";
|
|
4
4
|
import type { LoadedSkill } from "../capabilities/skills.js";
|
|
5
|
+
import type { CenterEndpoint } from "./center-request.js";
|
|
5
6
|
import type { CenterA2aPeer, CenterMcpServer, CenterSkillManifest } from "./types.js";
|
|
6
7
|
/**
|
|
7
8
|
* Merge center skills OVER the image baseline ([ref]-sibling B1; `sema-registry docs/MCP-SKILLS.md`). Load order =
|
|
@@ -13,7 +14,9 @@ import type { CenterA2aPeer, CenterMcpServer, CenterSkillManifest } from "./type
|
|
|
13
14
|
*/
|
|
14
15
|
export declare function applyCenterSkills(baseline: LoadedSkill[], manifest: {
|
|
15
16
|
skills: CenterSkillManifest[];
|
|
16
|
-
},
|
|
17
|
+
},
|
|
18
|
+
/** S-651:中心端点(基址 + 凭证来源;每次正文拉取取一次值)。 */
|
|
19
|
+
center: CenterEndpoint, logger?: Logger, fetchImpl?: typeof fetch,
|
|
17
20
|
/** LKG 姊妹面(clay 拍 2026-07-18):skill 正文的 content-addressed 盘缓存目录。读序=内存→盘(验
|
|
18
21
|
* hash,坏文件忽略)→中心(成功后 best-effort 回写)。让 LKG-boot 在中心不可达时不再于正文拉取上
|
|
19
22
|
* 挂数秒(live 实测黑洞 +5.3s/skill 批),顺带省正常 refresh 的重复拉取。undefined=无盘缓存(原行为)。 */
|
|
@@ -5,7 +5,7 @@ import { CONTENT_ORIGIN_WORDS, describeBadContentOrigin, isContentOriginWord } f
|
|
|
5
5
|
import { fetchSkillContent } from "./http-client.js";
|
|
6
6
|
import { SHA256_HEX_RE } from "../digest-form.js";
|
|
7
7
|
import { describeBadWireName, isUsableWireName } from "../wire-name-bound.js";
|
|
8
|
-
export async function applyCenterSkills(baseline, manifest,
|
|
8
|
+
export async function applyCenterSkills(baseline, manifest, center, logger, fetchImpl = fetch, diskCacheDir) {
|
|
9
9
|
const { promises: fsp } = await import("node:fs");
|
|
10
10
|
const { join: joinPath } = await import("node:path");
|
|
11
11
|
const diskRead = async (hash) => {
|
|
@@ -50,7 +50,7 @@ export async function applyCenterSkills(baseline, manifest, baseUrl, token, logg
|
|
|
50
50
|
if (content === undefined)
|
|
51
51
|
content = await diskRead(m.contentHash);
|
|
52
52
|
if (content === undefined) {
|
|
53
|
-
content = await fetchSkillContent(
|
|
53
|
+
content = await fetchSkillContent(center, m.contentHash, fetchImpl);
|
|
54
54
|
diskWrite(m.contentHash, content);
|
|
55
55
|
}
|
|
56
56
|
contentCache.set(m.contentHash, content);
|
|
@@ -303,7 +303,7 @@ export interface EffectiveConfig {
|
|
|
303
303
|
* settings-schema 0.6 起住 `governance` 域,0.7.1 撤了 runtime 位的双写镜像;此后 `RuntimeConfig` 是 strip
|
|
304
304
|
* 的 zod object,两条腿(远端 `readEffectiveWire` / 本地 FileConfigStore→`buildEffective`)都把旧位 strip
|
|
305
305
|
* 掉、由 `legacyGovernanceFromRuntime` 抬进 governance ⇒ 本仓在 runtime 位上读它们的每一行都是死码。
|
|
306
|
-
* 旧类型面上留着这三键,让 `runtime-gates` 重启片一直读着一个生产上恒缺席的位(审批闸收紧静默不生效)。 */
|
|
306
|
+
* 旧类型面上留着这三键,让(已于 S-668 波 2 退役的)`runtime-gates` 重启片一直读着一个生产上恒缺席的位(审批闸收紧静默不生效)。 */
|
|
307
307
|
runtime?: {
|
|
308
308
|
rateLimitPerMin?: number;
|
|
309
309
|
maxTaskCostUsd?: number;
|
|
@@ -342,8 +342,8 @@ export interface EffectiveConfig {
|
|
|
342
342
|
/** settings-schema 0.6 起治理三件(autonomy/commandPolicy/approvalRequire)的**唯一**承运域(0.7.1 撤
|
|
343
343
|
* runtime 位双写镜像;顺序契约当年已走完:消费端先切、center 再撤)。键集与 schema `GovernanceConfig.shape`
|
|
344
344
|
* 逐字相等([ref] 件3 对账门钉)。消费:autonomy/commandPolicy 逐请求热(`stageRuntimeHot`,boot+refresh);
|
|
345
|
-
* approvalRequire
|
|
346
|
-
* 同一 presence 规则(undefined = 不管 →
|
|
345
|
+
* approvalRequire 自 S-668 波 2 起同样热(`stageApprovalGate`,boot+refresh 双腿,有自己的拒绝臂)。
|
|
346
|
+
* 同一 presence 规则(undefined = 不管 → 回 env 基线,非粘)。 */
|
|
347
347
|
governance?: {
|
|
348
348
|
autonomy?: Autonomy;
|
|
349
349
|
commandPolicy?: CommandRule[];
|
|
@@ -28,9 +28,9 @@ import type { ServiceConfigFlat } from "./config-types.js";
|
|
|
28
28
|
*/
|
|
29
29
|
export declare const LIVENESS_HEARTBEAT_MS = 30000;
|
|
30
30
|
/** 闭集:新增一条不变量必须在这里加词(拼错 = 编译红,而不是运行期悄悄不判)。 */
|
|
31
|
-
export type CrossInvariantId = "run-stale-heartbeat" | "bind-posture" | "bake-runner-credential" | "direct-door-anchors" | "operator-principals-required" | "bake-operator-principals" | "sensitive-write-patterns" | "leader-host-lane" | "leader-durable-store" | "device-durable-store" | "device-durable-approval" | "model-provider-word" | "gateway-url-userinfo" | "model-route-endpoint" | "require-execution-lane"
|
|
31
|
+
export type CrossInvariantId = "run-stale-heartbeat" | "bind-posture" | "bake-runner-credential" | "direct-door-anchors" | "operator-principals-required" | "bake-operator-principals" | "sensitive-write-patterns" | "leader-host-lane" | "leader-durable-store" | "device-durable-store" | "device-durable-approval" | "model-provider-word" | "gateway-url-userinfo" | "model-route-endpoint" | "require-execution-lane";
|
|
32
32
|
/** 表读的键集(取自平铺配置型 ⇒ 键名/类型永不与真配置漂)。 */
|
|
33
|
-
export type CrossInvariantView = Readonly<Pick<ServiceConfigFlat, "runStaleSec" | "authToken" | "authTokens" | "allowUnauthedWrites" | "imageBakes" | "directApprovalDoor" | "durableApproval" | "approvalHmacKeys" | "principalJwtPubkeys" | "principalJwtIss" | "principalJwtAud" | "requirePrincipal" | "operatorPrincipals" | "sensitiveWritePatterns" | "leaderEnabled" | "remoteExec" | "requireExecutionLane" | "dbBackend" | "tidb" | "pg" | "envModel" | "gatewayBaseUrl" | "gatewayFallbackUrls" | "anthropic" | "models"
|
|
33
|
+
export type CrossInvariantView = Readonly<Pick<ServiceConfigFlat, "runStaleSec" | "authToken" | "authTokens" | "allowUnauthedWrites" | "imageBakes" | "directApprovalDoor" | "durableApproval" | "approvalHmacKeys" | "principalJwtPubkeys" | "principalJwtIss" | "principalJwtAud" | "requirePrincipal" | "operatorPrincipals" | "sensitiveWritePatterns" | "leaderEnabled" | "remoteExec" | "requireExecutionLane" | "dbBackend" | "tidb" | "pg" | "envModel" | "gatewayBaseUrl" | "gatewayFallbackUrls" | "anthropic" | "models">>;
|
|
34
34
|
export interface CrossInvariantInput {
|
|
35
35
|
/** 现役配置(boot 期 = 候选自身)。 */
|
|
36
36
|
readonly live: CrossInvariantView;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { assertGuardPatternsUsable } from "./deployment-governance.js";
|
|
2
|
-
import { hostedPrincipalRefusal } from "./hosted-posture.js";
|
|
3
2
|
import { modelProviderRefusal } from "./model-provider.js";
|
|
4
3
|
import { modelRouteUrlRefusal } from "./model-route-url.js";
|
|
5
4
|
import { modelRouteEndpointRefusal } from "./model-route-endpoint.js";
|
|
@@ -82,13 +81,6 @@ export const CONFIG_CROSS_INVARIANTS = [
|
|
|
82
81
|
? "IMAGE_BAKES_ENABLED with an EMPTY OPERATOR_PRINCIPALS is a world-writable bake door (the runner runs build.sh on the privileged build host)"
|
|
83
82
|
: undefined,
|
|
84
83
|
},
|
|
85
|
-
{
|
|
86
|
-
id: "hosted-requires-principal",
|
|
87
|
-
keys: ["requirePrincipal", "principalJwtPubkeys", "principalJwtIss", "principalJwtAud", "authBridgeIssuer"],
|
|
88
|
-
restartReason: "hosted-posture",
|
|
89
|
-
bootAnchor: { file: "src/config.ts", marker: "CROSS-INVARIANT:hosted-requires-principal" },
|
|
90
|
-
check: ({ next }) => hostedPrincipalRefusal(next),
|
|
91
|
-
},
|
|
92
84
|
{
|
|
93
85
|
id: "sensitive-write-patterns",
|
|
94
86
|
keys: ["sensitiveWritePatterns"],
|
package/dist/config-lkg.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/** 落盘信封。`effective`/`etag` 逐字=当时的 fetchEffective 返回(JSON verbatim 面)。 */
|
|
2
2
|
export interface PersistedLkg {
|
|
3
|
-
formatVersion:
|
|
3
|
+
formatVersion: 2;
|
|
4
4
|
savedAt: string;
|
|
5
5
|
worker: string;
|
|
6
|
+
/** 拉到这份候选时所用凭证的身份(`center-credential.ts`;摘要形,不含凭证原文)。 */
|
|
7
|
+
identity: string;
|
|
6
8
|
etag?: string;
|
|
7
9
|
effective: Record<string, unknown>;
|
|
8
10
|
}
|
|
@@ -10,21 +12,58 @@ export interface PersistedLkg {
|
|
|
10
12
|
* hash 另拉)——黑洞中心下 LKG-boot 会在 skill 正文拉取上再挂数秒(live 实测 +5.3s)。正文按
|
|
11
13
|
* `<dir>/<sha-hex>` 落盘,读侧**必验 hash**(content-addressed 的全部意义;坏文件=忽略重拉)。 */
|
|
12
14
|
export declare function defaultSkillCacheDir(): string;
|
|
13
|
-
/** 默认路径(scheduler store 同门:SEMA_CONFIG_DIR → ~/.sema)
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
export declare function defaultLkgPath(worker: string | undefined): string;
|
|
15
|
+
/** 默认路径(scheduler store 同门:SEMA_CONFIG_DIR → ~/.sema),按「worker + 凭证身份」分箱。`CONFIG_LKG_PATH`
|
|
16
|
+
* 覆写(单一路径 ⇒ 不分箱,信封的 worker + identity 核仍守读回);`CONFIG_LKG_ENABLED=false` 关闭(读写双关)。
|
|
17
|
+
* 🪦 正名前的 `CONFIG_LKG_DISABLED` 自 server 3.0.0 起是**fail-loud 墓碑**——设了(任何值)即拒启并指路新名,不再被读取。 */
|
|
18
|
+
export declare function defaultLkgPath(worker: string | undefined, identity: string): string;
|
|
17
19
|
/** 原子落盘一个干净候选(tmp+rename,0600)。BEST-EFFORT:失败=一条 warn 的素材(调用方发),绝不
|
|
18
20
|
* 影响在飞的应用链——LKG 缓存丢失的代价只是下次冷启动回到 env 兜底。 */
|
|
19
|
-
export declare function saveLkg(path: string, worker: string | undefined, effective: Record<string, unknown>, etag: string | undefined): Promise<void>;
|
|
21
|
+
export declare function saveLkg(path: string, worker: string | undefined, identity: string, effective: Record<string, unknown>, etag: string | undefined): Promise<void>;
|
|
20
22
|
/**
|
|
21
23
|
* 读盘上 LKG。返回 undefined 的所有情形都「安静地回 env 兜底」(调用方 warn 点名 reason):
|
|
22
|
-
* 文件缺席/JSON 坏/信封形不对/worker
|
|
24
|
+
* 文件缺席/JSON 坏/信封形不对/worker 或凭证身份不匹配(防同名文件跨 worker / 跨账号串包;`CONFIG_LKG_PATH`
|
|
25
|
+
* 单一路径时这是唯一的一道)/prompts 面复判失败。
|
|
23
26
|
*/
|
|
24
|
-
export declare function loadLkg(path: string, worker: string | undefined): Promise<{
|
|
27
|
+
export declare function loadLkg(path: string, worker: string | undefined, identity: string): Promise<{
|
|
25
28
|
lkg: PersistedLkg;
|
|
26
29
|
} | {
|
|
27
30
|
lkg?: undefined;
|
|
28
31
|
reason: string;
|
|
29
32
|
}>;
|
|
33
|
+
/** 7.98.0 及以前的默认 LKG 路径(按当时的写法逐字保留 —— 这是盘上已有文件的名字,不是现行分箱规则)。 */
|
|
34
|
+
export declare function legacyV1LkgPath(worker: string | undefined): string;
|
|
35
|
+
export type LegacyLkgMigration = {
|
|
36
|
+
readonly outcome: "none";
|
|
37
|
+
}
|
|
38
|
+
/** `retireError`:新箱已写好,只是旧文件没退役成(改名 / 留副本失败)—— 只响一行,不影响已写好的箱。 */
|
|
39
|
+
| {
|
|
40
|
+
readonly outcome: "migrated";
|
|
41
|
+
readonly from: string;
|
|
42
|
+
readonly retiredTo: string;
|
|
43
|
+
readonly retireError?: string;
|
|
44
|
+
} | {
|
|
45
|
+
readonly outcome: "not-migrated";
|
|
46
|
+
readonly path: string;
|
|
47
|
+
readonly reason: string;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* formatVersion 1 LKG 的一次性迁移(规则一句:**身份推得出来才迁,推不出来就响亮拒**)。判序:
|
|
51
|
+
* 1. `legacyPath` ≠ `binPath` 时**先看本身份的箱**:箱里已有文件 ⇒ `none`(箱自己说话,旧文件是好是坏都不再相关,
|
|
52
|
+
* 不许一个坏旧文件把有效的箱挡成 env 兜底 —— 7.99.0 修复验证 N4)。箱查不了(非 ENOENT)⇒ 响亮拒。
|
|
53
|
+
* 2. 旧文件没有(ENOENT / ENOTDIR)或不是 formatVersion 1 信封 ⇒ `none`。旧默认路径上却读不了 / 不是 JSON ⇒
|
|
54
|
+
* `not-migrated`(响亮,不当它不存在);`CONFIG_LKG_PATH` 同路径时这两形由 loadLkg 自己报(不重复打一行)。
|
|
55
|
+
* 3. v1 信封只记 worker:唯一推得出身份的形是拉取令牌(身份 = worker,`pullTokenIdentity`)。此刻身份正是它、worker
|
|
56
|
+
* 对得上、载荷过 {@link lkgPayloadProblem} ⇒ **先写后退役**(修复验证 N9):先按新格式把它写进 `binPath`(原子写,
|
|
57
|
+
* 0600),写成了才把旧文件改名 `<legacyPath>.migrated-v1`。写失败 ⇒ `not-migrated`,旧文件原样留在原位,下一次
|
|
58
|
+
* 照常可迁;写成之后改名失败 ⇒ 仍是 `migrated`(`retireError` 响一行),箱已在 ⇒ 下一次按判序 1 不再看旧文件。
|
|
59
|
+
* 同路径(`CONFIG_LKG_PATH`)时新箱的写入会原子替换旧文件本身,所以旧字节在写之前留一份 `.migrated-v1` 副本
|
|
60
|
+
* (副本失败同样只进 `retireError`:载荷正要写进新箱,不是丢数据)。
|
|
61
|
+
* 4. 其余一律 `not-migrated`:拒因点名旧文件路径与出路(删掉它;中心下一份干净候选会写本身份自己的 LKG),不改名、不读回。
|
|
62
|
+
*/
|
|
63
|
+
export declare function migrateV1Lkg(o: {
|
|
64
|
+
legacyPath: string;
|
|
65
|
+
binPath: string;
|
|
66
|
+
worker: string | undefined;
|
|
67
|
+
identity: string;
|
|
68
|
+
}): Promise<LegacyLkgMigration>;
|
|
30
69
|
//# sourceMappingURL=config-lkg.d.ts.map
|