@sema-agent/server 7.127.2 → 7.129.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 +130 -0
- package/USAGE.md +137 -20
- package/dist/approval-card.d.ts +53 -26
- package/dist/approval-card.js +40 -11
- package/dist/approval-crash-convergence.js +4 -4
- package/dist/audit.js +4 -1
- package/dist/bake-runner/main.js +2 -1
- package/dist/boot/execution-lane.d.ts +11 -0
- package/dist/boot/execution-lane.js +6 -0
- package/dist/boot/memory-consolidation.d.ts +46 -16
- package/dist/boot/memory-consolidation.js +15 -8
- package/dist/boot/resolve-spec.js +3 -1
- package/dist/boot/side-query-lane.d.ts +7 -20
- package/dist/boot/side-query-lane.js +0 -24
- package/dist/boot/stage-01-config.js +3 -0
- package/dist/boot/stage-06-runners.js +1 -1
- package/dist/boot/stores.js +2 -2
- package/dist/boot/web-admin.js +31 -20
- package/dist/boot/webfetch-summarize-lane.d.ts +10 -7
- package/dist/boot/webfetch-summarize-lane.js +2 -3
- package/dist/brain.js +6 -9
- package/dist/capabilities/builtin-tools.d.ts +2 -2
- package/dist/capabilities/engine-capabilities.d.ts +14 -0
- package/dist/capabilities/engine-capabilities.js +12 -0
- package/dist/capabilities/mcp-probe.js +11 -5
- package/dist/capability-facts.d.ts +3 -1
- package/dist/capability-facts.js +1 -0
- package/dist/config-catalog.js +1 -1
- package/dist/config-provider.d.ts +17 -4
- package/dist/config-provider.js +8 -6
- package/dist/config-types.d.ts +6 -5
- package/dist/egress-redirect.d.ts +12 -0
- package/dist/egress-redirect.js +7 -0
- package/dist/entry-mode-clamp-notice.d.ts +30 -0
- package/dist/entry-mode-clamp-notice.js +13 -0
- package/dist/fleet/fleet-bus.d.ts +7 -0
- package/dist/fleet/fleet-bus.js +1 -0
- package/dist/hooks/hook-llm.js +6 -2
- package/dist/hooks/hook-runner.d.ts +1 -0
- package/dist/hooks/hook-runner.js +10 -4
- package/dist/host-lsp-manager.d.ts +3 -3
- package/dist/http/admission.js +5 -2
- package/dist/http/resume-legs.js +46 -27
- package/dist/http/route-ctx.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.js +6 -4
- package/dist/http/routes/capabilities.js +1 -0
- package/dist/http/routes/session-sync.js +3 -4
- package/dist/http/routes/sessions.js +4 -17
- package/dist/http/send.d.ts +1 -1
- package/dist/http/send.js +4 -3
- package/dist/http/wire-types.d.ts +14 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/main.js +2 -0
- package/dist/mcp-assertion-header.d.ts +89 -0
- package/dist/mcp-assertion-header.js +49 -0
- package/dist/observability/fail-open.d.ts +7 -3
- package/dist/observability/fail-open.js +7 -3
- package/dist/observability/secret-env-scrub.d.ts +37 -3
- package/dist/observability/secret-env-scrub.js +2 -2
- package/dist/parked-decide.js +5 -2
- package/dist/plugins/host-platform.d.ts +43 -13
- package/dist/plugins/host-platform.js +67 -18
- package/dist/plugins/memory-embedder.js +5 -0
- package/dist/plugins/one-time-migrations.d.ts +180 -9
- package/dist/plugins/one-time-migrations.js +315 -3
- package/dist/plugins/pg-pool.js +3 -1
- package/dist/plugins/remote-env-host.d.ts +17 -20
- package/dist/plugins/remote-env-host.js +16 -28
- package/dist/plugins/session-policy-store-sql.d.ts +16 -4
- package/dist/plugins/session-policy-store-sql.js +17 -20
- package/dist/plugins/session-rules-column.d.ts +16 -0
- package/dist/plugins/session-rules-column.js +6 -0
- package/dist/plugins/tidb-pool.js +4 -1
- package/dist/read-face-posture.d.ts +2 -1
- package/dist/request-value-closure.js +1 -1
- package/dist/retired-card-words.d.ts +17 -0
- package/dist/retired-card-words.js +49 -0
- package/dist/rule-entry-list.js +2 -0
- package/dist/run-local.js +15 -6
- package/dist/server-secret-env.d.ts +77 -85
- package/dist/server-secret-env.js +40 -26
- package/dist/session-policy-wire.d.ts +61 -124
- package/dist/session-policy-wire.js +59 -121
- package/dist/session-sync.d.ts +8 -6
- package/dist/session-sync.js +6 -5
- package/dist/spec-fields.d.ts +3 -2
- package/dist/standing-answer-grant.d.ts +17 -9
- package/dist/standing-answer-grant.js +11 -8
- package/dist/task-mcp.d.ts +31 -3
- package/dist/task-mcp.js +42 -4
- package/dist/task-settings.d.ts +6 -1
- package/dist/task-settings.js +1 -1
- package/dist/tool-approval.d.ts +14 -7
- package/dist/tool-approval.js +23 -18
- package/dist/trace/core-keyset-guard.d.ts +3 -3
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +1 -0
- package/dist/trace/project.d.ts +7 -4
- package/dist/trace/project.js +7 -76
- package/dist/trace/tool-output-media.d.ts +10 -4
- package/dist/trace/tool-output-media.js +7 -29
- package/dist/web-admin-client/apply-effective.js +28 -11
- package/dist/web-admin-client/facade.d.ts +2 -2
- package/dist/web-admin-client/facade.js +2 -2
- package/dist/web-admin-client/http-client.d.ts +2 -2
- package/dist/web-admin-client/read-face.d.ts +73 -20
- package/dist/web-admin-client/read-face.js +76 -36
- package/dist/web-admin-client/skills-mcp.d.ts +20 -17
- package/dist/web-admin-client/skills-mcp.js +27 -8
- package/dist/web-admin-client/types.d.ts +18 -0
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { judgeSessionRulesWrite, readSessionRulesShape, SessionPolicyError } from "@sema-agent/core";
|
|
3
|
+
import { SESSION_RULES_COLUMN } from "./session-rules-column.js";
|
|
4
4
|
import { decodeJsonColumn, isJsonColumnBodyProblem, jsonColumnText } from "./sql-json-column.js";
|
|
5
5
|
import { pgHasUnstorable } from "./pg-safe-json.js";
|
|
6
6
|
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
@@ -8,9 +8,13 @@ import { isDeadlockError, isDupKeyError } from "./sql-errors.js";
|
|
|
8
8
|
export const policyKeyFor = (sessionId, principal) => createHash("sha256").update(JSON.stringify([sessionId, principal ?? null])).digest("hex");
|
|
9
9
|
const policyKey = policyKeyFor;
|
|
10
10
|
const RETRY_LIMIT = 8;
|
|
11
|
+
const RULES = SESSION_RULES_COLUMN.name;
|
|
11
12
|
export function readSessionRulesBody(body) {
|
|
12
|
-
const read =
|
|
13
|
-
|
|
13
|
+
const read = readSessionRulesShape(body);
|
|
14
|
+
if ("fault" in read)
|
|
15
|
+
return { problem: read.sentence };
|
|
16
|
+
const { grammar, ...buckets } = read.rules;
|
|
17
|
+
return { value: body.grammar === undefined ? buckets : { ...buckets, grammar } };
|
|
14
18
|
}
|
|
15
19
|
function readRulesBody(text, where) {
|
|
16
20
|
try {
|
|
@@ -29,7 +33,7 @@ function rowToStored(r, where) {
|
|
|
29
33
|
const counters = readRowCounters(r, where);
|
|
30
34
|
if ("problem" in counters)
|
|
31
35
|
throw new SessionPolicyError("corrupt", counters.problem);
|
|
32
|
-
return { ...readRulesBody(r
|
|
36
|
+
return { ...readRulesBody(r[RULES], `session_policy.rule_entries ${where}`), rev: counters.rev, gen: counters.gen };
|
|
33
37
|
}
|
|
34
38
|
function readRowCounters(r, where) {
|
|
35
39
|
const rev = Number(r.rev);
|
|
@@ -67,8 +71,8 @@ export class SqlSessionPolicyStore {
|
|
|
67
71
|
}
|
|
68
72
|
async getRules(sessionId, principal) {
|
|
69
73
|
const key = policyKey(sessionId, principal);
|
|
70
|
-
const { rows } = await this.db.query(this.q(`SELECT 'row' AS src, ${jsonColumnText("tidb",
|
|
71
|
-
" UNION ALL SELECT 'seal', NULL, rev, gen FROM session_policy_rev_mark WHERE policy_key = ? AND rev = ?", `SELECT 'row' AS src, ${jsonColumnText("pg",
|
|
74
|
+
const { rows } = await this.db.query(this.q(`SELECT 'row' AS src, ${jsonColumnText("tidb", RULES)}, rev, gen FROM session_policy WHERE policy_key = ?` +
|
|
75
|
+
" UNION ALL SELECT 'seal', NULL, rev, gen FROM session_policy_rev_mark WHERE policy_key = ? AND rev = ?", `SELECT 'row' AS src, ${jsonColumnText("pg", RULES)}, rev, gen FROM session_policy WHERE policy_key = $1` +
|
|
72
76
|
" UNION ALL SELECT 'seal', NULL, rev, gen FROM session_policy_rev_mark WHERE policy_key = $2 AND rev = $3"), [key, key, SEALED_MARK_REV]);
|
|
73
77
|
if (rows.some((r) => r.src === "seal"))
|
|
74
78
|
throw sealedKeyError(sessionId, `key ${key}`);
|
|
@@ -78,8 +82,8 @@ export class SqlSessionPolicyStore {
|
|
|
78
82
|
return rowToStored(row, `for session ${JSON.stringify(sessionId)}`);
|
|
79
83
|
}
|
|
80
84
|
async listBySession(sessionId) {
|
|
81
|
-
const { rows } = await this.db.query(this.q(`SELECT 'row' AS src, principal, ${jsonColumnText("tidb",
|
|
82
|
-
" UNION ALL SELECT 'seal', NULL, NULL, rev, gen FROM session_policy_rev_mark WHERE session_id = ? AND rev = ?", `SELECT 'row' AS src, principal, ${jsonColumnText("pg",
|
|
85
|
+
const { rows } = await this.db.query(this.q(`SELECT 'row' AS src, principal, ${jsonColumnText("tidb", RULES)}, rev, gen FROM session_policy WHERE session_id = ?` +
|
|
86
|
+
" UNION ALL SELECT 'seal', NULL, NULL, rev, gen FROM session_policy_rev_mark WHERE session_id = ? AND rev = ?", `SELECT 'row' AS src, principal, ${jsonColumnText("pg", RULES)}, rev, gen FROM session_policy WHERE session_id = $1` +
|
|
83
87
|
" UNION ALL SELECT 'seal', NULL, NULL, rev, gen FROM session_policy_rev_mark WHERE session_id = $2 AND rev = $3"), [sessionId, sessionId, SEALED_MARK_REV]);
|
|
84
88
|
if (rows.some((r) => r.src === "seal"))
|
|
85
89
|
throw sealedKeyError(sessionId, "one of its keys");
|
|
@@ -91,7 +95,7 @@ export class SqlSessionPolicyStore {
|
|
|
91
95
|
async putRules(sessionId, principal, rules, opts) {
|
|
92
96
|
const key = policyKey(sessionId, principal);
|
|
93
97
|
return this.retrying(() => this.tx(async (conn) => {
|
|
94
|
-
const { rows } = await conn.query(this.q(`SELECT ${jsonColumnText("tidb",
|
|
98
|
+
const { rows } = await conn.query(this.q(`SELECT ${jsonColumnText("tidb", RULES)}, rev, gen FROM session_policy WHERE policy_key = ? FOR UPDATE`, `SELECT ${jsonColumnText("pg", RULES)}, rev, gen FROM session_policy WHERE policy_key = $1 FOR UPDATE`), [key]);
|
|
95
99
|
const prior = rows[0] ? rowToStored(rows[0], `for session ${JSON.stringify(sessionId)} (pre-write snapshot)`) : undefined;
|
|
96
100
|
const priorRev = prior?.rev ?? 0;
|
|
97
101
|
if (opts?.expectedRev !== undefined && priorRev !== opts.expectedRev) {
|
|
@@ -103,14 +107,7 @@ export class SqlSessionPolicyStore {
|
|
|
103
107
|
if (markRows[0] !== undefined && (!isStoredCounter(markGen, 0) || !isStoredCounter(markRev, 0))) {
|
|
104
108
|
throw new SessionPolicyError("corrupt", `the session rules rev mark for session ${JSON.stringify(sessionId)} is unreadable (rev ${String(markRows[0].rev)}, gen ${String(markRows[0].gen)}) — refusing rather than stamp a rev/lineage nothing proves`);
|
|
105
109
|
}
|
|
106
|
-
const clean =
|
|
107
|
-
assertSessionRuleNamesCurrent(clean);
|
|
108
|
-
if (prior && opts?.operator !== true) {
|
|
109
|
-
const loosens = loosenReasons(prior, clean);
|
|
110
|
-
if (loosens.length > 0) {
|
|
111
|
-
throw new SessionPolicyError("loosen_forbidden", `a non-operator session-rule write may only tighten; refused: ${loosens.join("; ")}`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
110
|
+
const clean = judgeSessionRulesWrite(prior ?? null, rules, opts);
|
|
114
111
|
if (this.db.dialect === "pg" && pgHasUnstorable(clean)) {
|
|
115
112
|
throw new SessionPolicyError("loosen_forbidden", "rules contain unstorable bytes (NUL / lone surrogate) — refused; strip them at the source (authorization rules are never rewritten by the store)");
|
|
116
113
|
}
|
|
@@ -122,12 +119,12 @@ export class SqlSessionPolicyStore {
|
|
|
122
119
|
const json = JSON.stringify(clean);
|
|
123
120
|
const now = new Date();
|
|
124
121
|
if (prior) {
|
|
125
|
-
const upd = await conn.query(this.q(
|
|
122
|
+
const upd = await conn.query(this.q(`UPDATE session_policy SET principal = ?, ${RULES} = ?, rev = ?, gen = ?, updated_at = ? WHERE policy_key = ? AND rev = ?`, `UPDATE session_policy SET principal = $1, ${RULES} = $2::jsonb, rev = $3, gen = $4, updated_at = $5 WHERE policy_key = $6 AND rev = $7`), [principal ?? null, json, nextRev, nextGen, now, key, priorRev]);
|
|
126
123
|
if (upd.affected !== 1)
|
|
127
124
|
throw new SessionPolicyError("conflict", `session rules rev mismatch (expected ${opts?.expectedRev ?? priorRev}, have ${priorRev})`);
|
|
128
125
|
}
|
|
129
126
|
else {
|
|
130
|
-
await conn.query(this.q(
|
|
127
|
+
await conn.query(this.q(`INSERT INTO session_policy (policy_key, session_id, principal, ${RULES}, rev, gen, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)`, `INSERT INTO session_policy (policy_key, session_id, principal, ${RULES}, rev, gen, created_at, updated_at) VALUES ($1,$2,$3,$4::jsonb,$5,$6,$7,$8)`), [key, sessionId, principal ?? null, json, nextRev, nextGen, now, now]);
|
|
131
128
|
}
|
|
132
129
|
return structuredClone({ ...clean, rev: nextRev, gen: nextGen });
|
|
133
130
|
}));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `session_policy` 装会话规则的那一列 —— 列定义的**唯一属主**:中央 DDL(`tidb-pool.ts` / `pg-pool.ts` 的 `CREATE TABLE session_policy`)、
|
|
3
|
+
* SQL 会话规则店(`session-policy-store-sql.ts` 的读三处 + 写两处)与一次性迁移 M17(`one-time-migrations.ts`,存量库改列名)都内插这同一份,
|
|
4
|
+
* 于是新库建出来的列与存量库改出来的列逐字同形(起服列册探针比的是列名,形由这里保证)。
|
|
5
|
+
*
|
|
6
|
+
* 规则:**一列一文法**。这一列装的是引擎的规则条目文法(引擎 7.51.0 起 `toolDeny` / `toolAllow` 装规则条目 —— `Bash(rm:*)` 是一条拒 `rm` 的规则;
|
|
7
|
+
* `allowDirs` 装目录),读它的只有引擎那一只形读者(`readSessionRulesShape`)。按另一种文法读规则的副本(7.128.x 及以前:同名的 `rules` 列,
|
|
8
|
+
* 条目按整串工具名比,`Bash(rm:*)` 匹配不到任何工具)在这只库上**找不到一列可以读错**:它的每一条规则语句点名的列不存在 ⇒ 响亮失败;
|
|
9
|
+
* 它的二进制起服时列册探针判出缺列 / 多列 ⇒ 拒启。两样都不是「读成更少的规则」。
|
|
10
|
+
*/
|
|
11
|
+
export declare const SESSION_RULES_COLUMN: {
|
|
12
|
+
readonly name: "rule_entries";
|
|
13
|
+
readonly tidb: "rule_entries JSON NOT NULL";
|
|
14
|
+
readonly pg: "rule_entries JSONB NOT NULL";
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=session-rules-column.d.ts.map
|
|
@@ -7,6 +7,7 @@ import { TIDB_ADOPTION_LOG_STATEMENTS } from "./adoption-log-sql.js";
|
|
|
7
7
|
import { TIDB_PERMISSION_RULE_STATEMENTS } from "./permission-rule-store-sql.js";
|
|
8
8
|
import { TIDB_RETENTION_STATEMENTS } from "./retention-store-sql.js";
|
|
9
9
|
import { SESSION_META_INCARNATION_COLUMN } from "../session-incarnation.js";
|
|
10
|
+
import { SESSION_RULES_COLUMN } from "./session-rules-column.js";
|
|
10
11
|
import { SESSION_TITLE_MAX_CHARS } from "../session-row.js";
|
|
11
12
|
import { ensureIndexes } from "./ensure-index.js";
|
|
12
13
|
import { CENTRAL_SCHEMA_INDEXES } from "./schema-indexes.js";
|
|
@@ -413,7 +414,9 @@ export const SCHEMA_STATEMENTS = [
|
|
|
413
414
|
-- not part of the CAS/tighten logic — putRules just writes it. NULL = the session-wide row (principal
|
|
414
415
|
-- undefined). PRE-MIGRATION rows (E6 was new when the column landed) ⇒ NULL, i.e. read as session-wide.
|
|
415
416
|
principal VARCHAR(190) NULL,
|
|
416
|
-
rules
|
|
417
|
+
-- 会话规则(三只桶,引擎的规则条目文法)。列定义唯一属主 = src/plugins/session-rules-column.ts 的 SESSION_RULES_COLUMN(一列一文法:
|
|
418
|
+
-- 7.128.x 及以前这一列叫 rules、按整串工具名读;存量库由一次性迁移 M17 改名,带退役命令桶的行原样留着、读回判坏并逐行点名,见那份文件与 one-time-migrations.ts)。
|
|
419
|
+
${SESSION_RULES_COLUMN.tidb},
|
|
417
420
|
rev BIGINT NOT NULL,
|
|
418
421
|
-- gen (core 7.25.0 StoredSessionRules.gen, S-529 二期):这一行的**血统**。rev 只在一条血统内计数,
|
|
419
422
|
-- deleteBySession 终结血统并把下一代的号留在 session_policy_rev_mark.gen 上,于是活规则读者能把
|
|
@@ -57,7 +57,8 @@ export declare function readFaceForPosture(singleUserTurnkey: boolean): ReadFace
|
|
|
57
57
|
* `web-admin-client/restart-signal.ts` 的 `read-face` 片也不再为它签重启理由(判据同源 =
|
|
58
58
|
* `CENTER_READ_FACE_LIVE_KEYS`,由 core 的 `isSwappableDepSeat` 派生)。本句此前逐字写着
|
|
59
59
|
* 「(restart-to-apply)」—— G-7 抓获的那条过期断言,方向恰好是「让运维为一个已生效的变更重启 fleet」。
|
|
60
|
-
* ⚠️ 只说 `face` 这一席:三个 deny
|
|
60
|
+
* ⚠️ 只说 `face` 这一席:三个 deny 键同样是热换席(core 7.51.0 起,落配与换席同一条腿),但它们没有来源位,
|
|
61
|
+
* 那半场的话不在这条读面上。 */
|
|
61
62
|
export declare function readFaceSourceNote(source: ReadFaceSource): string;
|
|
62
63
|
/** operator 诊断面的投影(`GET /v1/diagnostics/wiring`)。`face:null` = 本部署没钉档,引擎默认接管。 */
|
|
63
64
|
export declare function buildReadFaceWiring(facts: ReadFacePostureFacts): {
|
|
@@ -25,7 +25,7 @@ export function singleMemberOffFieldIssue(raw) {
|
|
|
25
25
|
}
|
|
26
26
|
export const INHERIT_ENV_WORDS = ["all", "scrub"];
|
|
27
27
|
export const INHERIT_ENV_VALUE_MESSAGE = `inheritEnv must be one of ${INHERIT_ENV_WORDS.map((w) => JSON.stringify(w)).join(" | ")} when present ` +
|
|
28
|
-
`("all" = the model-driven host shell inherits this machine's whole environment, honored only on a single-user host-lane deployment; ` +
|
|
28
|
+
`("all" = the model-driven host shell inherits this machine's whole environment except this deployment's own credentials (its configuration directory's secret-typed names), honored only on a single-user host-lane deployment; ` +
|
|
29
29
|
`"scrub" = the default scrub of credential-shaped variables, accepted on every lane; absent = "scrub") — a name list is not a request value`;
|
|
30
30
|
export function inheritEnvFieldIssue(raw) {
|
|
31
31
|
if (raw === null || raw === undefined || typeof raw !== "object" || Array.isArray(raw))
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** 改写涉及的座(读侧半场的响亮诊断用;只报座名,不报值)。 */
|
|
2
|
+
export type RetiredCardWordSeat = "ruleOffersAbsence" | "askClass" | "classes";
|
|
3
|
+
/** 一次改写的结论:`seats` 为空 = 这一只载体上没有退役词(`value` 就是传入的那一只,同一引用)。 */
|
|
4
|
+
export interface RetiredCardWordsRewrite<T> {
|
|
5
|
+
readonly value: T;
|
|
6
|
+
readonly seats: readonly RetiredCardWordSeat[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 载着卡两座的那一只对象(存卡的 `card`、停驻行的 `tool_approval` 臂)上的退役词改写。不改原对象:有改写时交一只浅拷贝(停驻行靠这一条保证读侧零写)。
|
|
10
|
+
* 非对象 / 数组 ⇒ 原样(这不是一只载体)。
|
|
11
|
+
*/
|
|
12
|
+
export declare function retireCardWords<T>(carrier: T): RetiredCardWordsRewrite<T>;
|
|
13
|
+
/** 存卡信封(`{ schemaVersion, approvalId, card }`)上的改写:只改 `card` 那一只。 */
|
|
14
|
+
export declare function retireStoredCardWords<T>(envelope: T): RetiredCardWordsRewrite<T>;
|
|
15
|
+
/** 停驻行 `pendingAction` 上的改写:只认 `tool_approval` 臂(core:读工具字段之前先按 `kind` 分臂);别的臂原样。 */
|
|
16
|
+
export declare function retireParkArmWords<T>(pendingAction: T): RetiredCardWordsRewrite<T>;
|
|
17
|
+
//# sourceMappingURL=retired-card-words.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ASK_CLASSES } from "@sema-agent/core";
|
|
2
|
+
const RETIRED_RULE_OFFERS_ABSENCE = "shadowed";
|
|
3
|
+
const RETIRED_ASK_CLASS = "governance_unavailable";
|
|
4
|
+
const SUCCESSOR_ASK_CLASS = "rule_unreadable";
|
|
5
|
+
const classOrder = (c) => {
|
|
6
|
+
const i = ASK_CLASSES.indexOf(c);
|
|
7
|
+
return i === -1 ? ASK_CLASSES.length : i;
|
|
8
|
+
};
|
|
9
|
+
export function retireCardWords(carrier) {
|
|
10
|
+
if (carrier === null || typeof carrier !== "object" || Array.isArray(carrier))
|
|
11
|
+
return { value: carrier, seats: [] };
|
|
12
|
+
const src = carrier;
|
|
13
|
+
const seats = [];
|
|
14
|
+
const next = { ...src };
|
|
15
|
+
if (Object.hasOwn(src, "ruleOffersAbsence") && src.ruleOffersAbsence === RETIRED_RULE_OFFERS_ABSENCE) {
|
|
16
|
+
delete next.ruleOffersAbsence;
|
|
17
|
+
seats.push("ruleOffersAbsence");
|
|
18
|
+
}
|
|
19
|
+
const classes = src.classes;
|
|
20
|
+
const classesCarryRetired = Array.isArray(classes) && classes.includes(RETIRED_ASK_CLASS);
|
|
21
|
+
if (classesCarryRetired) {
|
|
22
|
+
const mapped = [...new Set(classes.map((c) => (c === RETIRED_ASK_CLASS ? SUCCESSOR_ASK_CLASS : c)))];
|
|
23
|
+
mapped.sort((a, b) => classOrder(a) - classOrder(b));
|
|
24
|
+
next.classes = mapped;
|
|
25
|
+
seats.push("classes");
|
|
26
|
+
if (Object.hasOwn(src, "askClass")) {
|
|
27
|
+
next.askClass = mapped[0];
|
|
28
|
+
seats.push("askClass");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else if (src.askClass === RETIRED_ASK_CLASS) {
|
|
32
|
+
next.askClass = SUCCESSOR_ASK_CLASS;
|
|
33
|
+
seats.push("askClass");
|
|
34
|
+
}
|
|
35
|
+
return seats.length === 0 ? { value: carrier, seats } : { value: next, seats };
|
|
36
|
+
}
|
|
37
|
+
export function retireStoredCardWords(envelope) {
|
|
38
|
+
if (envelope === null || typeof envelope !== "object" || Array.isArray(envelope))
|
|
39
|
+
return { value: envelope, seats: [] };
|
|
40
|
+
const env = envelope;
|
|
41
|
+
const card = retireCardWords(env.card);
|
|
42
|
+
return card.seats.length === 0 ? { value: envelope, seats: [] } : { value: { ...env, card: card.value }, seats: card.seats };
|
|
43
|
+
}
|
|
44
|
+
export function retireParkArmWords(pendingAction) {
|
|
45
|
+
if (pendingAction === null || typeof pendingAction !== "object" || pendingAction.kind !== "tool_approval")
|
|
46
|
+
return { value: pendingAction, seats: [] };
|
|
47
|
+
return retireCardWords(pendingAction);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=retired-card-words.js.map
|
package/dist/rule-entry-list.js
CHANGED
|
@@ -31,6 +31,8 @@ export function inertRuleEntryGuidance(i) {
|
|
|
31
31
|
return "this tool takes no content form here — name the tool itself, or use Bash(<command>) / Bash(<prefix>:*) for a shell command";
|
|
32
32
|
case "grammar":
|
|
33
33
|
return "the entry is not read as written (surrounding whitespace, an empty or unbalanced tool name, or an invisible or control character in the tool name) — write the tool name exactly, with no padding";
|
|
34
|
+
case "earlier_grammar":
|
|
35
|
+
throw new Error(`allow-entry inert reason ${JSON.stringify(reason)} belongs to the session-rule store's bucket reading (compileSessionRuleBucket), never to an allow-layer entry list — a caller handed a session-rule reading to the entry-list sentence`);
|
|
34
36
|
default: {
|
|
35
37
|
const unhandled = reason;
|
|
36
38
|
throw new Error(`unhandled allow-entry inert reason: ${String(unhandled)}`);
|
package/dist/run-local.js
CHANGED
|
@@ -25,10 +25,10 @@ import { acquireLocalBackendWithWait } from "./plugins/store-lock-wait.js";
|
|
|
25
25
|
import { configLocalRoot, configProviderKind, createConfigProvider } from "./config-provider.js";
|
|
26
26
|
import { CONFIG_DOMAIN_INVALID_NOTE, buildCandidateRejectedFields, judgeConfigCandidate } from "./web-admin-client/candidate-gate.js";
|
|
27
27
|
import { buildUnreadConfigFileFields } from "./web-admin-client/read-warnings.js";
|
|
28
|
-
import { composeExecutionLane } from "./boot/execution-lane.js";
|
|
28
|
+
import { composeExecutionLane, settleHostLaneShell } from "./boot/execution-lane.js";
|
|
29
29
|
import { judgeConsolidationValve } from "./boot/memory-consolidation.js";
|
|
30
30
|
import { logConfigDirMigration, migrateLocalConfigDirectory } from "./config-d-migration.js";
|
|
31
|
-
import { applyEffective, applyCenterReadFace, resolveMcpServers, mcpForScenario, resolveA2aPeers, a2aForScenario } from "./web-admin-client/facade.js";
|
|
31
|
+
import { applyEffective, applyCenterReadFace, applySkillsManifest, resolveMcpServers, mcpForScenario, resolveA2aPeers, a2aForScenario } from "./web-admin-client/facade.js";
|
|
32
32
|
import { hostExecutionEnvFactory } from "./plugins/remote-env-host.js";
|
|
33
33
|
import { executionLaneHomeDir, executionLaneOf } from "./execution-lane-caps.js";
|
|
34
34
|
import { makeLoadProjectMemory, makeProbeInstructionSources } from "./project-memory.js";
|
|
@@ -60,6 +60,7 @@ import { createHostLspManager } from "./host-lsp-manager.js";
|
|
|
60
60
|
import { buildDisplaySafeUrl } from "./trace/redact.js";
|
|
61
61
|
import { installOutboundDispatcher } from "./outbound-dispatcher.js";
|
|
62
62
|
import { provisionSemaConfigDir } from "./sema-config-dir.js";
|
|
63
|
+
import { bindOwnCredentialsConfig, declareServerWithheldEnv } from "./server-secret-env.js";
|
|
63
64
|
export function parseArgs(argv) {
|
|
64
65
|
let objective;
|
|
65
66
|
let root;
|
|
@@ -152,7 +153,6 @@ export const NO_TTY_ASK_CLASS_ROW = {
|
|
|
152
153
|
unverifiable_shell_text: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
153
154
|
transcript_write: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
154
155
|
org_rule: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
155
|
-
governance_unavailable: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
156
156
|
rule_unreadable: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
157
157
|
ask_rule: { remedy: "approval_lists", autoBudgetReleases: true },
|
|
158
158
|
denial_limit_fallback: { remedy: "terminal_only", autoBudgetReleases: false },
|
|
@@ -327,7 +327,9 @@ export async function runLocal(argv, deps = {}) {
|
|
|
327
327
|
process.env.REQUIRE_PRINCIPAL = "false";
|
|
328
328
|
if (args.root)
|
|
329
329
|
process.env.CONFIG_LOCAL_DIR = args.root;
|
|
330
|
+
declareServerWithheldEnv();
|
|
330
331
|
const config = loadConfig();
|
|
332
|
+
bindOwnCredentialsConfig(config);
|
|
331
333
|
const root = configLocalRoot(config);
|
|
332
334
|
const logger = deps.logger ?? createLogger(config.logLevel);
|
|
333
335
|
const metrics = createMetrics();
|
|
@@ -350,6 +352,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
350
352
|
const configProvider = createConfigProvider(providerInput);
|
|
351
353
|
let effective;
|
|
352
354
|
let candidatePrompts;
|
|
355
|
+
let applying = false;
|
|
353
356
|
try {
|
|
354
357
|
const r = await configProvider.fetchEffective(undefined);
|
|
355
358
|
if (r) {
|
|
@@ -364,9 +367,10 @@ export async function runLocal(argv, deps = {}) {
|
|
|
364
367
|
logger.warn("config_unread_file", buildUnreadConfigFileFields(f, configProvider.kind === "local" ? root : undefined));
|
|
365
368
|
for (const d of r.droppedEntries ?? [])
|
|
366
369
|
logger.warn("config_entry_dropped", { domain: d.domain, entry: d.entry, reasonCode: d.reasonCode, error: d.error, version: r.effective.version, phase: "boot", note: "this one entry failed its domain schema and was dropped on its own — the rest of the candidate applies (per-entry tolerance); fix the named entry to bring it back" });
|
|
370
|
+
applying = true;
|
|
371
|
+
applyEffective(config, r.effective, logger, { leg: "boot" });
|
|
367
372
|
effective = r.effective;
|
|
368
373
|
candidatePrompts = verdict.prompts;
|
|
369
|
-
applyEffective(config, r.effective, logger, { leg: "boot" });
|
|
370
374
|
if (effective?.mcp)
|
|
371
375
|
config.mcpServers = resolveMcpServers(effective.mcp, logger);
|
|
372
376
|
if (effective?.a2a)
|
|
@@ -377,7 +381,10 @@ export async function runLocal(argv, deps = {}) {
|
|
|
377
381
|
}
|
|
378
382
|
}
|
|
379
383
|
catch (err) {
|
|
380
|
-
|
|
384
|
+
if (applying)
|
|
385
|
+
logger.warn("config_apply_refused", { source: configProvider.kind, err: String(err), note: "the candidate failed to apply at boot — running on env (run-local has no LKG); none of the candidate's domains is adopted; this is not a reachability failure" });
|
|
386
|
+
else
|
|
387
|
+
logger.warn("config_source_unreachable_using_env", { source: configProvider.kind, err: String(err) });
|
|
381
388
|
}
|
|
382
389
|
const noDefaultModel = defaultModelRefusal(config, "env");
|
|
383
390
|
if (noDefaultModel !== undefined)
|
|
@@ -436,6 +443,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
436
443
|
const keyResolver = createKeyResolver(config.modelApiKeyEnv, process.env, config.modelApiKeys);
|
|
437
444
|
const hostRx = config.remoteExec?.provider === "host" ? config.remoteExec : undefined;
|
|
438
445
|
const workspaceDir = args.workspace ?? hostRx?.workspaceBase ?? process.cwd();
|
|
446
|
+
await settleHostLaneShell(config, logger);
|
|
439
447
|
const executionEnvFactory = hostRx
|
|
440
448
|
? hostExecutionEnvFactory({
|
|
441
449
|
workspaceDir,
|
|
@@ -595,7 +603,8 @@ export async function runLocal(argv, deps = {}) {
|
|
|
595
603
|
const subRunnerDeps = { ...sharedRunnerDeps, sessionStore: new ForkRoutingSessionStore(sessionStore, new TtlSessionStore({ defaultTtlDays: 1 / 24 })), onError: engineOnError, onAsk };
|
|
596
604
|
const subRunner = new Runner(subRunnerDeps);
|
|
597
605
|
const handslessRunner = new Runner(withoutHands(runnerDeps));
|
|
598
|
-
const
|
|
606
|
+
const deploymentSkills = loadDeploymentSkills(config);
|
|
607
|
+
const skills = effective?.skills ? await applySkillsManifest(deploymentSkills, effective.skills, configProvider, logger) : deploymentSkills;
|
|
599
608
|
const repoClient = config.gitApiBaseUrl ? createRepoClient(config.gitApiKind, config.gitApiBaseUrl, config.gitApiToken) : undefined;
|
|
600
609
|
const webSearchCfg = webSearchConfigFromEnv();
|
|
601
610
|
const webSearch = webSearchCfg ? createWebSearchBackend(webSearchCfg) : undefined;
|
|
@@ -1,115 +1,107 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 7.
|
|
3
|
-
* S-684 残余按类收口)起也是本包**宿主子进程 env 的唯一组合点**。
|
|
2
|
+
* 宿主子进程 env 的**唯一组合点**(7.103.0 起,S-684 残余按类收口)+ 本进程**自有凭据名的唯一声明点**(7.129.0 起,core 7.51.1)。
|
|
4
3
|
*
|
|
5
|
-
* ## 病
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* git(`leader/wire.ts`)、center-plugins 克隆的 git(`capabilities/center-plugins.ts`)、bake-runner 交给 build.sh 与主机命令的
|
|
12
|
-
* env(`bake-runner/main.ts`,连 runner 自己的 `BAKE_RUNNER_TOKEN`)。
|
|
4
|
+
* ## 病(沿革)
|
|
5
|
+
* 7.99.0 合并复审 F7(web-admin [ref] 实测;安全轴;DEBTS S-684):core 的形状剥(`*_KEY` / `*_TOKEN` …)认不出本仓自己的凭据键
|
|
6
|
+
* (`SERVICE_AUTH_TOKENS` / `APPROVAL_HMAC_KEYS` / `OTEL_EXPORTER_OTLP_HEADERS`)⇒ 本仓在 `scrub` 腿上另加目录臂按名剥。7.129.0(web-client
|
|
7
|
+
* 实测):目录臂只在 `scrub` 腿施,`inheritEnv:"all"` 是 `{ ...process.env }` 零剥除、`[names]` 点到目录 secret 名照放 —— 单用户 host 上 cli 交互 lane
|
|
8
|
+
* 每次提交发 `"all"`,引擎自己的 `SERVICE_AUTH_TOKEN(S)` / `APPROVAL_HMAC_KEYS` / `MODEL_API_KEY` 逐字进模型 shell,模型一条 `curl` 可自批自己的 HITL 卡。
|
|
9
|
+
* 病根是本仓自判三个继承词、而只在其中一个词上减自有凭据。
|
|
13
10
|
*
|
|
14
|
-
* ##
|
|
15
|
-
* 本包任何进程在宿主上 spawn 的子进程:env =
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* `
|
|
30
|
-
*
|
|
11
|
+
* ## 律(一句;core #1753 定,本仓只传事实、不判)
|
|
12
|
+
* 本包任何进程在宿主上 spawn 的子进程:env = 引擎 `inheritedHostEnv(policy, findings)` ∪ 部署方点名放回的键(只在运维真可能要传东西的腿上有旋钮),
|
|
13
|
+
* 剥掉的键经一个登记过的 `SecretEnvScrubSite` 留痕;git 腿再叠 git 自己的两件({@link gitSubprocessEnv})。三个继承词只在引擎一处判:
|
|
14
|
+
* · `"all"` = 整份环境 **减** 本进程声明的自有凭据名;`"scrub"`(缺省)= 形状剥 ∪ 该名单;`[names]` = 严格白名单,点到名单中的名 ⇒ 引擎响亮拒
|
|
15
|
+
* (`inheritEnvPolicyProblem`:构造时与 spawn 时两格都拒,拒句带名;本仓不自判 withheld、不留第二读法)。
|
|
16
|
+
* · 名单 = 配置目录(`config-catalog.ts`)全部 `type:"secret"` 名 ∪ 名单型旋钮名(`env-name-allowlist-knobs.ts`,其原文可能夹着被错展开的令牌)∪ **生效配置
|
|
17
|
+
* 模型条目的 `apiKeyEnv`**(key-resolver 取凭据的那张表 `config.modelApiKeyEnv` 的值 —— 本进程消费的凭据变量名,条目由中心热应用新增 / 改名),
|
|
18
|
+
* **机器派生**、不手抄、不按「归谁消费」切({@link serverWithheldEnvNames} 一处)。声明两个时机、同一只 {@link declareServerWithheldEnv}:起服第一步(三个进程入口:
|
|
19
|
+
* `boot/stage-01-config.ts` / `run-local.ts` / `bake-runner/main.ts`,在任何执行环境构造与 spawn 之前 —— 声明先于构造才有构造时拒;此时没有生效配置 = 空表),
|
|
20
|
+
* 与每次生效配置换代(`web-admin-client/apply-effective.ts` 本体:CAS 之后、Runner 换装与 commit 之前 —— 声明先于席位,旧世代不声明)。名单只随**落地**的世代
|
|
21
|
+
* 增长(本进程 env 是 boot 期输入:一个名字一旦指过本进程的凭据,条目改名 / 删掉之后它的值仍在 env 里 ⇒ 落地过的名不退出;没落地的候选不留痕 —— 换装拒 ⇒
|
|
22
|
+
* {@link withdrawServerWithheldEnv} 撤回到换代前的集合)。声明失败(坏形名 / 运行时回填名)⇒ 引擎抛且声明保持原状:起服那次 = 拒启,换代那次 = 候选整拒(与 stage
|
|
23
|
+
* 抛同路)。能力词 `inherit_env.own_credentials_withheld` 在本进程的事实 =
|
|
24
|
+
* {@link ownCredentialsWithheld}:最近一次成功声明的集合 ⊇ 当前生效配置应声明的集合(活配置经 {@link bindOwnCredentialsConfig} 在 `loadConfig()` 之后绑一次;
|
|
25
|
+
* 未绑 / 未声明 ⇒ false,事实读不到应声明集合就不答 true)。
|
|
26
|
+
* · 调用方显式传入的 env(`cfg.env` / 单次命令的 `env` / 语言服务器与沙箱的点名放回)不是继承,照旧原样叠在组合结果之上 —— 那是适配器自己的凭据通道。
|
|
27
|
+
* 各腿只调 {@link hostSubprocessEnv} / {@link gitSubprocessEnv} —— 不许再有内联拼装、不许再有 `{ ...process.env }`、不许本仓再判任何一个继承词
|
|
28
|
+
* (类级门在 `test/secret-env-scrub-host-legs.test.ts`)。
|
|
31
29
|
*
|
|
32
30
|
* ## 点名放行(S-699 / S-713,一只谓词各处用)
|
|
33
|
-
* {@link allowlistedEnv} 是本仓「一张名单点到哪些 env 键,就把它们从源 env **原样**交给子进程」的唯一实现。调用:
|
|
34
|
-
*
|
|
35
|
-
*
|
|
31
|
+
* {@link allowlistedEnv} 是本仓「一张名单点到哪些 env 键,就把它们从源 env **原样**交给子进程」的唯一实现。调用:{@link hostSubprocessEnv}(剥后放回形:
|
|
32
|
+
* 本地语言服务器的 `LSP_ENV_ALLOW`、bake-runner 的 `BAKE_ENV_ALLOW`)、沙箱带外 env 的 `E2B_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` / `K8S_SANDBOX_ENV`(`config.ts`)。
|
|
33
|
+
* host shell 的 `inheritEnv:[names]`(hermetic 形)7.129.0 起由引擎读(与 core `NodeExecutionEnv` 同名选项同义,点到自有凭据名即拒),不经本谓词。
|
|
36
34
|
* 名单型旋钮的**名单**另由 `config.ts` 的同一只解析器 `parseEnvNameAllowlist` 判形(形错拒启 / 源里没有的名按序号 warn),本函数只管取值。
|
|
37
35
|
* 「点名」在各处同义:点到的键原样带值(空串值照带),密钥形也照过(点名 = 部署方显式承担);源里没有的名不产生条目。
|
|
38
|
-
*
|
|
39
|
-
* host shell 与「剥后放回」形**只在没点到的键上**不同,这是有意保留的差别:host shell 的 `string[]` 形是 hermetic 白名单(与 core
|
|
40
|
-
* `NodeExecutionEnv` 同名选项同义,没点到的一律不继承);语言服务器 / bake-runner 在 {@link scrubServerSecrets} 的结果之上放回点名键
|
|
41
|
-
* (没点到的照缺省剥,`PATH` / `HOME` 这类非密钥键照常在 —— hermetic 形会让子进程当场找不到自己的工具链)。
|
|
42
|
-
* 两形都不放宽对方:把 host shell 改成「剥后放回」= 在模型可驱动的 shell 上放宽,把后者改成 hermetic = 功能当场失灵。
|
|
36
|
+
* ⚠️ 已知边界(不在本函数修):`LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW` 点到自有凭据名会把它放回语言服务器 / 配方脚本(剥后放回形在引擎的减法之上);解析器今天只拒名单型旋钮名。
|
|
43
37
|
*/
|
|
44
|
-
import { type SecretEnvFinding } from "@sema-agent/core";
|
|
38
|
+
import { type InheritEnvPolicy, type SecretEnvFinding } from "@sema-agent/core";
|
|
39
|
+
import type { ServiceConfig } from "./config-types.js";
|
|
45
40
|
import { type SecretEnvScrubSite } from "./observability/secret-env-scrub.js";
|
|
46
|
-
/**
|
|
47
|
-
* `source` 用本仓自己的词 `server-config-catalog`,与 core 的 `secret-env` 分开 —— 读观测面的人要分得清
|
|
48
|
-
* 「形状规则剥的」与「本仓目录点名剥的」(后者多出来的那部分正是 core 形状规则的缺口)。 */
|
|
49
|
-
export interface CatalogSecretEnvFinding {
|
|
50
|
-
readonly key: string;
|
|
51
|
-
readonly kind: "config-catalog";
|
|
52
|
-
readonly confidence: "high";
|
|
53
|
-
readonly source: "server-config-catalog";
|
|
54
|
-
}
|
|
55
|
-
/** 名单型旋钮臂的一条剥除记录(形同上;`source` 用自己的词 —— 读观测面的人要分得清「目录点名剥的」与「名单型旋钮原文按凭据类剥的」)。 */
|
|
56
|
-
export interface NameListKnobEnvFinding {
|
|
57
|
-
readonly key: string;
|
|
58
|
-
readonly kind: "name-list-knob";
|
|
59
|
-
readonly confidence: "high";
|
|
60
|
-
readonly source: "server-name-list-knob";
|
|
61
|
-
}
|
|
62
|
-
/** 本仓子进程腿的扣下记录:core 的形状臂 ∪ 本仓的目录臂 ∪ 名单型旋钮臂。 */
|
|
63
|
-
export type ServerSecretEnvFinding = SecretEnvFinding | CatalogSecretEnvFinding | NameListKnobEnvFinding;
|
|
64
|
-
/** 配置目录里 `type:"secret"` 的 env 名(大写 —— Windows 的 env 名不分大小写,按大写比才不会漏)。 */
|
|
41
|
+
/** 配置目录里 `type:"secret"` 的 env 名(按目录原文 —— 引擎按平台比名:POSIX 逐字、Windows 不分大小写,本仓不再另折叠)。 */
|
|
65
42
|
export declare const CATALOG_SECRET_ENV_NAMES: ReadonlySet<string>;
|
|
43
|
+
/** 生效配置模型条目 name → `apiKeyEnv`(变量**名**,值从本进程 env 取)—— `ServiceConfig.modelApiKeyEnv` 的形,key-resolver 读凭据的那张表。 */
|
|
44
|
+
export type ModelApiKeyEnvTable = Readonly<Record<string, string>>;
|
|
66
45
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
46
|
+
* 本进程的自有凭据名(机器派生,三臂一处:目录 secret 名 ∪ 名单型旋钮名 ∪ `modelApiKeyEnv` 表的值;排序只为读数稳定)。纯函数:给哪张表就答哪张表的应声明
|
|
47
|
+
* 集合 —— 声明时给候选表、能力位给活表,同一只派生。名字按原文交引擎(目录臂同形),不在本仓折叠大小写。
|
|
48
|
+
*/
|
|
49
|
+
export declare function serverWithheldEnvNames(modelApiKeyEnv?: ModelApiKeyEnvTable): readonly string[];
|
|
50
|
+
/**
|
|
51
|
+
* 🔴 **唯一声明点**:把本进程自有凭据名向引擎声明(core `declareWithheldEnv`;重声明即替换,从下一次 spawn 起生效)。`modelApiKeyEnv` = 这一次要并进名单的模型条目表
|
|
52
|
+
* (起服第一步 = 空表;换代 = 候选表),名单 = 此前声明过的 ∪ 这张表的应声明集合 —— 名单只随**落地**的世代增长:落地过的名不再退出(改名 / 删条目之后它的值仍在
|
|
53
|
+
* 本进程 env 里),没落地的候选不留痕(旧世代在 CAS 处就拒、不到这里;换装拒 ⇒ {@link withdrawServerWithheldEnv})。引擎对坏形名 / 运行时回填名(`PATH` / `HOME` /
|
|
54
|
+
* `USER` …)响亮抛且声明保持原状 —— 本函数不接住:起服那次抛 = 拒启;换代那次抛 = 候选整拒(`applyEffective` 抛,与 stage 抛同路)。返回声明的名单(只名、不值)。
|
|
55
|
+
*/
|
|
56
|
+
export declare function declareServerWithheldEnv(modelApiKeyEnv?: ModelApiKeyEnvTable): readonly string[];
|
|
57
|
+
/**
|
|
58
|
+
* 席位拒 ⇒ 撤回最近一次声明(回到它之前的集合):`applyEffective` 在 Runner 换装抛时调,紧跟着那一次 {@link declareServerWithheldEnv} —— 没落地的候选不留痕。
|
|
59
|
+
* 退回去的集合是引擎之前接受过的(判名确定)⇒ 不抛;连撤两次是同一个结果(幂等)。
|
|
75
60
|
*/
|
|
76
|
-
export declare function
|
|
61
|
+
export declare function withdrawServerWithheldEnv(): void;
|
|
62
|
+
/** 把活配置交给能力位读(stage-01 / run-local 在 `loadConfig()` 之后各一次;读的是 `config.modelApiKeyEnv` 这个**属性**,commit 整表重赋值之后看到的就是新表)。 */
|
|
63
|
+
export declare function bindOwnCredentialsConfig(config: Pick<ServiceConfig, "modelApiKeyEnv">): void;
|
|
64
|
+
/**
|
|
65
|
+
* 能力词 `inherit_env.own_credentials_withheld` 在本进程的事实:最近一次成功声明的集合 ⊇ 当前生效配置应声明的集合。是一次比较,不是「声明过」的旗 ——
|
|
66
|
+
* 活表若被谁绕过声明写了新名,这里立刻 false(位不替流程担保)。没绑活配置 / 没声明过 ⇒ false(fail-closed)。
|
|
67
|
+
*/
|
|
68
|
+
export declare function ownCredentialsWithheld(): boolean;
|
|
69
|
+
/** 测试缝:撤回声明(引擎侧重声明为空)、忘掉声明集合(含撤回格)与活配置;生产代码从不调它。 */
|
|
70
|
+
export declare function __resetServerWithheldEnvForTest(): void;
|
|
71
|
+
/** 一条宿主腿要什么:现场(留痕)、继承策略(缺省 `"scrub"`;只有模型可驱动的 host shell 交非缺省词)、部署方点名放回的键。 */
|
|
72
|
+
export interface HostSubprocessEnvRequest {
|
|
73
|
+
readonly site: SecretEnvScrubSite;
|
|
74
|
+
readonly policy?: InheritEnvPolicy | undefined;
|
|
75
|
+
readonly allow: readonly string[];
|
|
76
|
+
}
|
|
77
77
|
/**
|
|
78
|
-
* 🔴 **宿主子进程 env
|
|
79
|
-
*
|
|
80
|
-
* 不是剥除,不计数、不披露)。源 env 只在入参 `sourceEnv` 绑定一次(缺省 `process.env`):剥除源、放回源、谓词回读三处读的是同一份映射。`sourceEnv` 是测试缝 ——
|
|
81
|
-
* `src/` 里的调用一律缺省(只带一个实参;钉:`test/secret-env-scrub-host-legs.test.ts` 类级门「opus 验修 L-1」格),平台尾参取缺省的推理只在源 = 本进程 env 时成立。
|
|
82
|
-
* (入参不叫 `env`:D1 对账门按标识符名在全文件收 `= process.env` 缺省参数的别名,叫 `env` 会把 {@link allowlistedEnv} 的同名形参一并认成别名、多记一处动态读。)
|
|
78
|
+
* 🔴 **宿主子进程 env 的唯一组合**:{@link composeHostSubprocessEnv} + 留痕。**没有按原样交给子进程**的名字(剥掉的)经 `site` 留痕;点名放回的键取回源值,
|
|
79
|
+
* 不是剥除,不计数、不披露。源 env 恒为本进程 env(引擎只读 `process.env`,本仓没有第二个源)。
|
|
83
80
|
*
|
|
84
|
-
* 六条宿主腿都只经它(直接或经 {@link gitSubprocessEnv}):host shell
|
|
81
|
+
* 六条宿主腿都只经它(直接或经 {@link gitSubprocessEnv}):host shell(三个继承词原样交给 `policy`)、project-memory / center-plugins / leader 三条 git 腿、
|
|
85
82
|
* 本地语言服务器、bake-runner 的每一只子进程组。`allow` 只在**有部署级出路**的现场非空(今天 = `LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW`,
|
|
86
83
|
* 它们的现场在 `SECRET_ENV_SCRUB_SITES` 里登记了 `remedy`,披露行因此是 warn + 放行名单 + 出路句);其余现场传 `[]`。
|
|
87
84
|
* 返回 `NodeJS.ProcessEnv` 形(值可能是 `undefined` 的键本来就不会进子进程);调用方显式要交的键(`LC_ALL`、`cfg.env` …)叠在它之上。
|
|
88
85
|
* 调用时机 = 每次要交 env 时现算一次(`process.env` 在本仓是 boot 期输入,各次同值;计数因此是「每组合一次」)。
|
|
86
|
+
* 引擎对坏策略 / 点到自有凭据名的白名单在这里**抛**(spawn 时的拒是不变量;构造时的拒由各构造点自己先问 `inheritEnvPolicyProblem`)。
|
|
89
87
|
*
|
|
90
|
-
* 🔴 **git 的 env 配置族与代理变量一族只有 core 一只写手**:core 7.35.0 #1201(S-877
|
|
91
|
-
* `
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* `GIT_CONFIG_` 这一族的名字(钉:`test/secret-env-git-config-pair.test.ts`「一只写手」格)。
|
|
96
|
-
* 🔴 **披露谓词 = 「这个名字没有按原样交给子进程」**(输入值 vs 输出值)。core 对一个变量的动作恒为「整只删」(从不改写值,#1201),点名放回的名字
|
|
97
|
-
* 取回源值 ⇒ 与输入同值 ⇒ 不是剥除。一只谓词盖住「剥掉」「点名放回」两形,不按形分臂(7.33.6–7.33.8 还有第三形「换占位」,随 #1201 消失)。
|
|
88
|
+
* 🔴 **git 的 env 配置族与代理变量一族只有 core 一只写手**:core 7.35.0 #1201(S-877)起它们是 core 的**豁免族** —— `GIT_CONFIG_COUNT` / `GIT_CONFIG_PARAMETERS` /
|
|
89
|
+
* `GIT_CONFIG_KEY_<数字>` / `GIT_CONFIG_VALUE_<数字>`(大写)与 `http(s)_proxy` / `all_proxy` / `no_proxy` / `npm_config_*proxy` …(任意大小写),名与值都不读、
|
|
90
|
+
* **原样交出,凭据在内**(部署面:凭据不放本进程 env —— `docs/DEPLOY-PREREQS.md`)。本仓不重判;本进程自有凭据名单不含这两族的名字
|
|
91
|
+
* (钉:`test/secret-env-git-config-pair.test.ts`「一只写手」格)。
|
|
92
|
+
* 🔴 **披露谓词 = 「这个名字没有按原样交给子进程」**(输入值 vs 输出值)。引擎对一个变量的动作恒为「整只删」(从不改写值),点名放回的名字取回源值 ⇒ 与输入同值 ⇒ 不是剥除。
|
|
98
93
|
*/
|
|
99
|
-
export declare function hostSubprocessEnv(o:
|
|
100
|
-
site: SecretEnvScrubSite;
|
|
101
|
-
allow: readonly string[];
|
|
102
|
-
}, sourceEnv?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
94
|
+
export declare function hostSubprocessEnv(o: HostSubprocessEnvRequest): NodeJS.ProcessEnv;
|
|
103
95
|
/**
|
|
104
96
|
* {@link hostSubprocessEnv} 的**组合本体**(不披露、不计数)—— 同一只组合,两个入口:真要交给子进程的现场经 `hostSubprocessEnv`(组合 + 披露);
|
|
105
97
|
* 只想知道「子进程**会**拿到什么」的读者(core 7.49.0 #1554:host 车道的 `ExecutionEnv.cdPath` 要报子进程真拿到的 `CDPATH`)读这一只 ——
|
|
106
|
-
* 既不另写一份组合(第二份会漂),也不把一次没发生的 spawn
|
|
98
|
+
* 既不另写一份组合(第二份会漂),也不把一次没发生的 spawn 记进剥除计数。`findings` 是组合点自己的收集器(引擎把形状臂与自有凭据臂的每一条扣下都推进去)。
|
|
107
99
|
*/
|
|
108
|
-
export declare function composeHostSubprocessEnv(
|
|
100
|
+
export declare function composeHostSubprocessEnv(o: Omit<HostSubprocessEnvRequest, "site">, findings?: SecretEnvFinding[]): NodeJS.ProcessEnv;
|
|
109
101
|
/** git 子进程腿的现场(闭集里名字带 `.git-` 的那几只 —— 编译期筛;它们都没有点名放行面)。 */
|
|
110
102
|
export type GitSubprocessSite = Extract<SecretEnvScrubSite, `${string}.git-${string}`>;
|
|
111
103
|
/**
|
|
112
|
-
* 宿主 **git 子进程**的 env:{@link hostSubprocessEnv}(site, 不放回) + `GIT_TERMINAL_PROMPT=0`(恒:凭据缺席 ⇒ 响亮失败,绝不挂在交互
|
|
104
|
+
* 宿主 **git 子进程**的 env:{@link hostSubprocessEnv}(site, 缺省 scrub, 不放回) + `GIT_TERMINAL_PROMPT=0`(恒:凭据缺席 ⇒ 响亮失败,绝不挂在交互
|
|
113
105
|
* prompt 上 —— 服务进程没有终端)+(`isolateConfig` ⇒ `GIT_CONFIG_GLOBAL` / `GIT_CONFIG_SYSTEM` = `/dev/null`:宿主全局 / 系统 git 配置
|
|
114
106
|
* (insteadOf / credential helper / hooksPath / fsmonitor …)一概不继承)。
|
|
115
107
|
*
|