@sema-agent/server 7.102.0 → 7.103.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.
Files changed (55) hide show
  1. package/MIGRATION.md +61 -0
  2. package/README.md +3 -3
  3. package/README.zh-CN.md +3 -3
  4. package/USAGE.md +99 -6
  5. package/dist/background-session-reap.d.ts +4 -1
  6. package/dist/bake-runner/main.d.ts +21 -3
  7. package/dist/bake-runner/main.js +18 -11
  8. package/dist/boot/config-center.d.ts +7 -2
  9. package/dist/boot/config-center.js +18 -4
  10. package/dist/boot/stage-01-config.js +2 -0
  11. package/dist/boot/stage-10-http-server.js +6 -1
  12. package/dist/brain.d.ts +28 -8
  13. package/dist/brain.js +20 -4
  14. package/dist/capabilities/center-plugins.d.ts +9 -3
  15. package/dist/capabilities/center-plugins.js +5 -10
  16. package/dist/config-catalog.js +9 -5
  17. package/dist/config-center/apply-effective.d.ts +16 -0
  18. package/dist/config-center/apply-effective.js +23 -11
  19. package/dist/config-center/mcp-revocation.d.ts +2 -2
  20. package/dist/config-center/mcp-revocation.js +1 -1
  21. package/dist/config-center/restart-signal.d.ts +0 -10
  22. package/dist/config-center/restart-signal.js +2 -12
  23. package/dist/config-types.d.ts +35 -17
  24. package/dist/config-types.js +3 -3
  25. package/dist/config.d.ts +7 -0
  26. package/dist/config.js +43 -17
  27. package/dist/env-name-allowlist-knobs.d.ts +21 -7
  28. package/dist/env-name-allowlist-knobs.js +7 -2
  29. package/dist/fleet-client.d.ts +9 -3
  30. package/dist/fleet-client.js +2 -0
  31. package/dist/host-lsp-manager.d.ts +4 -3
  32. package/dist/host-lsp-manager.js +2 -6
  33. package/dist/http/dispatch.js +4 -0
  34. package/dist/http/server.d.ts +4 -0
  35. package/dist/leader/wire.d.ts +8 -1
  36. package/dist/leader/wire.js +4 -3
  37. package/dist/model-entry-refusal.d.ts +31 -9
  38. package/dist/model-entry-refusal.js +22 -10
  39. package/dist/model-route-endpoint.d.ts +10 -0
  40. package/dist/model-route-endpoint.js +6 -2
  41. package/dist/observability/secret-env-scrub.d.ts +12 -0
  42. package/dist/observability/secret-env-scrub.js +12 -0
  43. package/dist/outbound-dispatcher.d.ts +125 -0
  44. package/dist/outbound-dispatcher.js +211 -0
  45. package/dist/plugins/host-platform.d.ts +6 -1
  46. package/dist/plugins/remote-env-host.js +3 -11
  47. package/dist/project-memory.js +3 -6
  48. package/dist/run-local.js +2 -0
  49. package/dist/server-secret-env.d.ts +97 -24
  50. package/dist/server-secret-env.js +37 -1
  51. package/dist/trace/core-keyset-guard.d.ts +6 -1
  52. package/dist/trace/project.js +13 -0
  53. package/dist/trace/redact.d.ts +11 -0
  54. package/dist/trace/redact.js +1 -0
  55. package/package.json +4 -3
@@ -1,5 +1,7 @@
1
1
  import { scrubSecretEnv } from "@sema-agent/core";
2
2
  import { CONFIG_CATALOG } from "./config-catalog.js";
3
+ import { ENV_NAME_ALLOWLIST_KNOB_NAMES } from "./env-name-allowlist-knobs.js";
4
+ import { recordSecretEnvScrub } from "./observability/secret-env-scrub.js";
3
5
  export const CATALOG_SECRET_ENV_NAMES = new Set(CONFIG_CATALOG.filter((spec) => spec.type === "secret").map((spec) => spec.name.toUpperCase()));
4
6
  export function scrubServerSecrets(env, findings) {
5
7
  const shapeFindings = [];
@@ -7,14 +9,48 @@ export function scrubServerSecrets(env, findings) {
7
9
  findings.push(...shapeFindings);
8
10
  const out = {};
9
11
  for (const key of Object.keys(shaped)) {
10
- if (CATALOG_SECRET_ENV_NAMES.has(key.toUpperCase())) {
12
+ const upper = key.toUpperCase();
13
+ if (CATALOG_SECRET_ENV_NAMES.has(upper)) {
11
14
  findings.push({ key, kind: "config-catalog", confidence: "high", source: "server-config-catalog" });
12
15
  continue;
13
16
  }
17
+ if (ENV_NAME_ALLOWLIST_KNOB_NAMES.has(upper)) {
18
+ findings.push({ key, kind: "name-list-knob", confidence: "high", source: "server-name-list-knob" });
19
+ continue;
20
+ }
14
21
  out[key] = shaped[key];
15
22
  }
16
23
  return out;
17
24
  }
25
+ export function hostSubprocessEnv(o) {
26
+ const scrubFindings = [];
27
+ const composed = { ...scrubServerSecrets(process.env, scrubFindings), ...allowlistedEnv(o.allow, process.env) };
28
+ const stripped = scrubFindings.filter((f) => composed[f.key] === undefined);
29
+ const grouped = withholdBrokenGitConfigGroup(process.env, composed).map((key) => ({ key, kind: "git-config-group", confidence: "high", source: "server-git-config-group" }));
30
+ recordSecretEnvScrub(o.site, [...stripped, ...grouped], o.allow);
31
+ return composed;
32
+ }
33
+ const GIT_CONFIG_GROUP_MEMBER_RE = /^GIT_CONFIG_(?:COUNT|(?:KEY|VALUE)_\d+)$/;
34
+ function withholdBrokenGitConfigGroup(source, composed) {
35
+ const isMember = (k) => GIT_CONFIG_GROUP_MEMBER_RE.test(k.toUpperCase());
36
+ const sourceMembers = new Set(Object.keys(source).filter(isMember).map((k) => k.toUpperCase()));
37
+ if (!sourceMembers.has("GIT_CONFIG_COUNT"))
38
+ return [];
39
+ const composedMembers = Object.keys(composed).filter(isMember);
40
+ const present = new Set(composedMembers.map((k) => k.toUpperCase()));
41
+ if ([...sourceMembers].every((m) => present.has(m)))
42
+ return [];
43
+ for (const k of composedMembers)
44
+ delete composed[k];
45
+ return composedMembers;
46
+ }
47
+ export function gitSubprocessEnv(o) {
48
+ return {
49
+ ...hostSubprocessEnv({ site: o.site, allow: [] }),
50
+ GIT_TERMINAL_PROMPT: "0",
51
+ ...(o.isolateConfig ? { GIT_CONFIG_GLOBAL: "/dev/null", GIT_CONFIG_SYSTEM: "/dev/null" } : {}),
52
+ };
53
+ }
18
54
  export function allowlistedEnv(names, env) {
19
55
  const out = {};
20
56
  for (const name of names) {
@@ -59,7 +59,7 @@ type _GuardMailboxReverse = AssertAllKeysHandled<Exclude<MailboxProjected, keyof
59
59
  type MailboxAppendProjected = "from" | "content" | "sentAt" | "hopChain" | "peerMeta";
60
60
  type _GuardMailboxAppend = AssertAllKeysHandled<Exclude<keyof MailboxAppendMessage, MailboxAppendProjected>>;
61
61
  type _GuardMailboxAppendReverse = AssertAllKeysHandled<Exclude<MailboxAppendProjected, keyof MailboxAppendMessage>>;
62
- type WiringSectionProjected = "schemaVersion" | "leg" | "ask" | "question" | "interaction" | "elicit" | "parkLane" | "session" | "fleet" | "permissionRules" | "modelGate" | "autoMode" | "mcp" | "tools" | "hooks" | "lsp" | "writeProtection" | "teamRole";
62
+ type WiringSectionProjected = "schemaVersion" | "leg" | "ask" | "question" | "interaction" | "elicit" | "parkLane" | "session" | "fleet" | "permissionRules" | "modelGate" | "autoMode" | "mcp" | "tools" | "hooks" | "lsp" | "hands" | "writeProtection" | "teamRole";
63
63
  type WiringSectionExcluded = "governance" | "configFingerprint" | "autoConsolidation" | "readDeny" | "peerPresence" | "fileHistory";
64
64
  type _GuardWiringSections = AssertAllKeysHandled<Exclude<keyof WiringManifest, WiringSectionProjected | WiringSectionExcluded>>;
65
65
  type _GuardWiringSectionsReverse = AssertAllKeysHandled<Exclude<WiringSectionProjected | WiringSectionExcluded, keyof WiringManifest>>;
@@ -104,6 +104,9 @@ type _GuardWiringMcpLivenessReverse = AssertAllKeysHandled<Exclude<WiringMcpLive
104
104
  type WiringRulesHandled = "storeWired" | "syncWired" | "orgGoverned";
105
105
  type _GuardWiringRules = AssertAllKeysHandled<Exclude<keyof WiringSection<"permissionRules">, WiringRulesHandled>>;
106
106
  type _GuardWiringRulesReverse = AssertAllKeysHandled<Exclude<WiringRulesHandled, keyof WiringSection<"permissionRules">>>;
107
+ type WiringHandsHandled = "mounted" | "reason";
108
+ type _GuardWiringHands = AssertAllKeysHandled<Exclude<keyof WiringSection<"hands">, WiringHandsHandled>>;
109
+ type _GuardWiringHandsReverse = AssertAllKeysHandled<Exclude<WiringHandsHandled, keyof WiringSection<"hands">>>;
107
110
  type WiringWriteProtectionHandled = "targetView";
108
111
  type _GuardWiringWriteProtection = AssertAllKeysHandled<Exclude<keyof WiringSection<"writeProtection">, WiringWriteProtectionHandled>>;
109
112
  type _GuardWiringWriteProtectionReverse = AssertAllKeysHandled<Exclude<WiringWriteProtectionHandled, keyof WiringSection<"writeProtection">>>;
@@ -236,6 +239,8 @@ export type CoreKeysetGuards = [
236
239
  _GuardWiringSections,
237
240
  _GuardWiringWriteProtection,
238
241
  _GuardWiringWriteProtectionReverse,
242
+ _GuardWiringHands,
243
+ _GuardWiringHandsReverse,
239
244
  _GuardWiringReadDeny,
240
245
  _GuardWiringReadDenyReverse,
241
246
  _GuardWiringAutoConsolidation,
@@ -521,6 +521,18 @@ export function wiringManifestEventData(ev) {
521
521
  const lane = str(lspIn.lane);
522
522
  return { mounted, ...(lane === undefined ? {} : { lane }) };
523
523
  })();
524
+ const handsIn = sec(m.hands);
525
+ const hands = (() => {
526
+ if (m.hands === undefined)
527
+ return undefined;
528
+ if (handsIn === undefined)
529
+ return dropProjectedFace("wiring_manifest.hands is not an object");
530
+ const mounted = bool(handsIn.mounted);
531
+ if (mounted === undefined)
532
+ return dropProjectedFace("wiring_manifest.hands.mounted is not a boolean");
533
+ const reason = str(handsIn.reason);
534
+ return { mounted, ...(reason === undefined ? {} : { reason }) };
535
+ })();
524
536
  const wpIn = sec(m.writeProtection);
525
537
  const writeProtection = (() => {
526
538
  if (m.writeProtection === undefined)
@@ -560,6 +572,7 @@ export function wiringManifestEventData(ev) {
560
572
  ...(mcp !== undefined ? { mcp } : {}),
561
573
  ...(hooks !== undefined ? { hooks } : {}),
562
574
  ...(lsp !== undefined ? { lsp } : {}),
575
+ ...(hands !== undefined ? { hands } : {}),
563
576
  ...(writeProtection !== undefined ? { writeProtection } : {}),
564
577
  ...identityFields(ev),
565
578
  };
@@ -61,6 +61,17 @@ export declare function armPoolBudgetForTest(): {
61
61
  ssh2ScanBytes: number;
62
62
  };
63
63
  export declare function resetArmPoolBudgetForTest(): void;
64
+ /** 本模块会写进文本的全部替换 token(`«…»` 字面),从三张表现算 —— 表改这里自动跟,不另抄一份。
65
+ * 🔴 **S-223 v2 修复轮起它只剩一个语义:闭形闭集的加载期校验**。运行期「这一段是不是一枚记号」已经由
66
+ * {@link credentialSpans} 的闭**形**那一支一处答完({@link opaqueUnitEnd}),按闭**集**再认一遍的
67
+ * `redactionTokenEndAt` 与它同义而更窄,已删 —— 两只「什么算记号」的判别器就是两个定义。 */
68
+ /** {@link buildDisplaySafeUrl} 解析不动一个配置型 URL 时的**占位**(S-475 件B)——fail-closed:输出**不含原串的
69
+ * 任何字节**(连 host 都不留),不许回落成原值。它不是任何一条臂的产物,所以要在这里**显式**进闭集
70
+ * {@link REDACTION_TOKENS}(闭形的加载期校验对它同样成立),消费端按契约 §5.1 的闭形逐枚解析时认得它。 */
71
+ declare const DISPLAY_SAFE_URL_TOKEN = "\u00ABredacted:url\u00BB";
72
+ /** S-776:出网代理 URL 的回显尺(`outbound-dispatcher.ts` `displayProxyUrl`)形不干净时整只用**同一枚**占位 —— 单独一行导出,
73
+ * 上面那行字面量保持 `const NAME = "…";` 形(`test/api-notice-text-freeze.test.ts` §6 的冻结扫描按这一形认替换 token)。 */
74
+ export { DISPLAY_SAFE_URL_TOKEN };
64
75
  /** 测试可见:扫描器 indexOf 实际扫过的字节数(摊还线性 ⇒ ≤ 常数 × 输入长)。 */
65
76
  export declare function ppkScanBytesForTest(): number;
66
77
  export declare function resetPpkScanBytesForTest(): void;
@@ -1091,6 +1091,7 @@ const FRAGMENT_SECRET_PATTERNS = [
1091
1091
  [valueArm("xapp-\\d-", "[A-Za-z0-9-]", 4, "needs-left-boundary"), "«redacted:slack-token:partial»"],
1092
1092
  ];
1093
1093
  const DISPLAY_SAFE_URL_TOKEN = "«redacted:url»";
1094
+ export { DISPLAY_SAFE_URL_TOKEN };
1094
1095
  const WITHHELD_VALUE_TOKEN = "«redacted»";
1095
1096
  const REDACTION_TOKENS = new Set([...FULL_ARM_PATTERNS.map(([, r]) => r), PEM_FRAGMENT_TOKEN, DISPLAY_SAFE_URL_TOKEN, ...FRAGMENT_SECRET_PATTERNS.map(([, r]) => r)]
1096
1097
  .flatMap((r) => r.match(/«[^»]*»/g) ?? []));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/server",
3
- "version": "7.102.0",
3
+ "version": "7.103.0",
4
4
  "description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -61,14 +61,15 @@
61
61
  "build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
62
62
  },
63
63
  "dependencies": {
64
- "@sema-agent/core": "7.32.1",
65
- "@sema-agent/settings-schema": "6.1.0",
64
+ "@sema-agent/core": "7.33.4",
65
+ "@sema-agent/settings-schema": "6.2.0",
66
66
  "e2b": "^2.28.0",
67
67
  "libsodium-wrappers": "^0.8.4",
68
68
  "mysql2": "^3.22.4",
69
69
  "pg": "^8.22.0",
70
70
  "ssh2": "^1.17.0",
71
71
  "typebox": "1.1.39",
72
+ "undici": "7.30.0",
72
73
  "ws": "^8.21.0",
73
74
  "zod": "^4.4.3"
74
75
  },