@sema-agent/settings-schema 10.1.1 → 11.1.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/CHANGELOG.md +469 -1
- package/README.md +144 -66
- package/bin/settings-schema.mjs +10 -12
- package/conformance/VERSION +1 -1
- package/conformance/baseline.json +3 -1
- package/conformance/cases/c01-entry-salvage-then-typo/expected.json +3 -1
- package/conformance/cases/c02-hosts-clamp-stacked/expected.json +12 -5
- package/conformance/cases/c02-hosts-clamp-stacked/meta.json +1 -1
- package/conformance/cases/c03-literal-dotted-top-key/expected.json +22 -2
- package/conformance/cases/c04-all-bad-collection-not-salvaged/expected.json +3 -1
- package/conformance/cases/c06-legacy-governance-lift/expected.json +11 -101
- package/conformance/cases/c06-legacy-governance-lift/meta.json +1 -1
- package/conformance/cases/c07-hooks-is-not-a-config-domain/expected.json +3 -1
- package/conformance/cases/c08-limits-unknown-carried-64/expected.json +203 -2
- package/conformance/cases/c09-limits-unknown-carried-65/expected.json +204 -2
- package/conformance/cases/c10-record-key-secret-redacted-twice/expected.json +3 -1
- package/conformance/cases/c11-unicode-unknown-keys/expected.json +20 -2
- package/conformance/cases/c12-prototype-name-top-keys/expected.json +3 -1
- package/conformance/cases/c13-models-field-null/expected.json +3 -1
- package/conformance/cases/c14-models-field-empty-array/expected.json +6 -1
- package/conformance/cases/c15-models-field-number/expected.json +3 -1
- package/conformance/cases/c16-deep-nesting-205/expected.json +14 -2
- package/conformance/cases/c17-empty-domain-file/expected.json +3 -1
- package/conformance/cases/c18-wire-envelope-not-an-object/expected.json +3 -1
- package/conformance/cases/c19-wire-envelope-no-version/expected.json +3 -1
- package/conformance/cases/c20-governance-absent-lifts/expected.json +11 -86
- package/conformance/cases/c20-governance-absent-lifts/meta.json +1 -1
- package/conformance/cases/c21-governance-empty-object-wins/expected.json +6 -5
- package/conformance/cases/c21-governance-empty-object-wins/input.json +1 -4
- package/conformance/cases/c21-governance-empty-object-wins/meta.json +1 -1
- package/conformance/cases/c23-mixed-validity-models/expected.json +3 -1
- package/conformance/cases/c24-valid-entries-with-unknown-keys/expected.json +22 -2
- package/conformance/cases/c25-published-roundtrip-zero-warnings/expected.json +6 -1
- package/conformance/cases/c26-hosts-array-1024/expected.json +3 -1
- package/conformance/cases/c27-hosts-array-1025/expected.json +6 -7175
- package/conformance/cases/c27-hosts-array-1025/meta.json +1 -1
- package/conformance/cases/c28-large-document-over-1mb/expected.json +14 -2
- package/conformance/cases/c29-salvage-then-domain-refine-fails/expected.json +3 -1
- package/conformance/cases/c30-version-triple-a-first/expected.json +6 -1
- package/conformance/cases/c31-version-triple-b-changed/expected.json +6 -1
- package/conformance/cases/c32-version-triple-a-restored/expected.json +6 -1
- package/conformance/cases/c33-limits-nested-carried-key/expected.json +18 -2
- package/conformance/cases/c34-skills-content-vs-manifest/expected.json +19 -3
- package/conformance/cases/c35-portable-domain-file-is-null/expected.json +3 -1
- package/conformance/cases/c36-skills-entry-without-content/expected.json +6 -2
- package/conformance/cases/c37-skills-field-null/expected.json +6 -2
- package/conformance/cases/c38-remote-exec-is-a-non-domain-file/expected.json +3 -1
- package/conformance/cases/c39-hidden-file-in-config-d/expected.json +3 -1
- package/conformance/cases/c40-s712-identity-only-what-reads-out/expected.json +11 -4
- package/conformance/cases/c41-s792-encoded-pem-identity/expected.json +9 -3
- package/conformance/cases/c42-s792-unknown-key-secret-redacted/expected.json +39 -2
- package/conformance/cases/c43-s792-form-and-deep-encoded-pem/expected.json +4 -1
- package/conformance/cases/c44-s792-utf8-escape-glued-token/expected.json +3 -1
- package/conformance/cases/c45-s792-identity-bounds-and-decode-depth/expected.json +19 -10
- package/conformance/cases/c45-s792-identity-bounds-and-decode-depth/meta.json +1 -1
- package/conformance/cases/{c46-s811-host-name-url-userinfo-characterization → c46-s811-host-name-url-userinfo-withheld}/expected.json +12 -5
- package/conformance/cases/c46-s811-host-name-url-userinfo-withheld/meta.json +9 -0
- package/conformance/cases/{c47-s811-roles-key-url-userinfo-characterization → c47-s811-roles-key-url-userinfo-withheld}/expected.json +23 -3
- package/conformance/cases/{c47-s811-roles-key-url-userinfo-characterization → c47-s811-roles-key-url-userinfo-withheld}/input.json +6 -0
- package/conformance/cases/c47-s811-roles-key-url-userinfo-withheld/meta.json +10 -0
- package/conformance/cases/c48-s935-model-headers-transported/expected.json +6 -1
- package/conformance/cases/c49-s935-model-headers-secret-entry-dropped/expected.json +3 -1
- package/conformance/cases/c50-s784-lane-host-legal/expected.json +3 -1
- package/conformance/cases/c51-s784-lane-e2b-legal/expected.json +3 -1
- package/conformance/cases/c52-s784-lane-k8s-legal/expected.json +3 -1
- package/conformance/cases/c53-s784-lane-ssh-legal/expected.json +3 -1
- package/conformance/cases/c54-s784-lane-adb-legal/expected.json +3 -1
- package/conformance/cases/c55-s784-lane-local-docker-legal/expected.json +3 -1
- package/conformance/cases/c56-s784-lane-device-legal/expected.json +3 -1
- package/conformance/cases/c57-s784-g1-enabled-no-lane/expected.json +3 -1
- package/conformance/cases/c58-s784-g2-multitenant-host/expected.json +3 -1
- package/conformance/cases/c59-s784-g3-k8s-missing-image/expected.json +3 -1
- package/conformance/cases/c60-s784-g3-e2b-missing-key/expected.json +3 -1
- package/conformance/cases/c61-s784-g3-other-lane-key/expected.json +3 -1
- package/conformance/cases/c62-s784-g7a-session-tidb/expected.json +3 -1
- package/conformance/cases/c63-s784-host-two-replicas/expected.json +3 -1
- package/conformance/cases/c64-s784-multitenant-local-store/expected.json +3 -1
- package/conformance/cases/c65-s784-pg-without-db/expected.json +3 -1
- package/conformance/cases/c66-s784-memory-backend-mismatch/expected.json +3 -1
- package/conformance/cases/c67-s784-retired-field-loud/expected.json +3 -1
- package/conformance/cases/c67-s784-retired-field-loud/meta.json +1 -1
- package/conformance/cases/c68-s784-device-local-store/expected.json +3 -1
- package/conformance/cases/c69-deep-encoded-token-past-every-reading/expected.json +3 -1
- package/conformance/cases/c70-rewritten-token-in-front-of-encoded-pem-header/expected.json +3 -1
- package/conformance/cases/c71-one-scanner-write-reads-display-forms/expected.json +119 -0
- package/conformance/cases/c71-one-scanner-write-reads-display-forms/input.json +24 -0
- package/conformance/cases/c71-one-scanner-write-reads-display-forms/meta.json +10 -0
- package/conformance/cases/c72-dangling-reference-write-seat-refuses/expected.json +111 -0
- package/conformance/cases/c72-dangling-reference-write-seat-refuses/input.json +26 -0
- package/conformance/cases/c72-dangling-reference-write-seat-refuses/meta.json +6 -0
- package/conformance/cases/cc01-mcp-toolfaces-non-object/expected.json +3 -1
- package/conformance/cases/cc02-mcp-source-key-is-transported/expected.json +3 -1
- package/conformance/cases/cc03-model-compat-unknown-subkey/expected.json +6 -1
- package/conformance/cases/cli01-model-name-nfc-vs-nfd/expected.json +11 -1
- package/conformance/cases/cli02-control-and-zero-width-chars/expected.json +11 -1
- package/conformance/cases/cli03-credential-pasted-into-unknown-key/expected.json +16 -2
- package/conformance/cases/cli04-env-value-with-newline/expected.json +3 -1
- package/conformance/cases/cli05-long-and-prefix-colliding-names/expected.json +6 -1
- package/conformance/cases/t01-absent-domain-key-not-null/expected.json +3 -1
- package/conformance/cases/t03-prototype-name-key-not-swallowed/expected.json +29 -2
- package/conformance/cases/t04-secret-literal-never-in-warning-value/expected.json +3 -1
- package/conformance/cases/z01-every-domain-empty-object/expected.json +8 -4
- package/conformance/cases/z01-every-domain-empty-object/input.json +0 -1
- package/conformance/cases/z01-every-domain-empty-object/meta.json +1 -1
- package/conformance/cases/z02-every-domain-unknown-key/expected.json +163 -23
- package/conformance/cases/z02-every-domain-unknown-key/input.json +0 -3
- package/conformance/cases/z02-every-domain-unknown-key/meta.json +1 -1
- package/dist/api/auth-bridge.d.ts +51 -181
- package/dist/api/auth-bridge.js +58 -33
- package/dist/api/auth.d.ts +37 -146
- package/dist/api/auth.js +16 -26
- package/dist/api/feedback.d.ts +87 -0
- package/dist/api/feedback.js +66 -0
- package/dist/api/pull-token.d.ts +32 -0
- package/dist/api/pull-token.js +88 -0
- package/dist/api/scopes.d.ts +82 -174
- package/dist/api/scopes.js +23 -18
- package/dist/atomic-write.d.ts +14 -0
- package/dist/atomic-write.js +60 -0
- package/dist/bundle.d.ts +15 -7
- package/dist/bundle.js +28 -27
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +149 -80
- package/dist/config-d-file.d.ts +14 -0
- package/dist/config-d-file.js +67 -0
- package/dist/config-fns.d.ts +87 -186
- package/dist/config-fns.js +207 -262
- package/dist/conformance/contract-adapter.d.ts +9 -2
- package/dist/conformance/contract-adapter.js +15 -7
- package/dist/conformance/corpus.d.ts +3 -0
- package/dist/conformance/corpus.js +5 -0
- package/dist/conformance/derive.d.ts +3 -0
- package/dist/conformance/index.d.ts +2 -2
- package/dist/conformance/index.js +2 -2
- package/dist/conformance/run.js +67 -22
- package/dist/conformance/types.d.ts +31 -15
- package/dist/conformance/types.js +5 -0
- package/dist/conformance/warnings.d.ts +1 -1
- package/dist/conformance/warnings.js +1 -4
- package/dist/cross-domain.d.ts +66 -22
- package/dist/cross-domain.js +164 -93
- package/dist/cross-session.d.ts +29 -11
- package/dist/default-model.d.ts +43 -0
- package/dist/default-model.js +34 -0
- package/dist/execution-lane-index.d.ts +4 -8
- package/dist/execution-lane-index.js +4 -8
- package/dist/execution-lanes.d.ts +31 -8
- package/dist/execution-lanes.js +23 -5
- package/dist/file-edit.d.ts +3 -3
- package/dist/file-edit.js +11 -18
- package/dist/file-store.d.ts +7 -6
- package/dist/file-store.js +37 -50
- package/dist/fleet.d.ts +364 -762
- package/dist/fleet.js +277 -224
- package/dist/hooks.d.ts +1151 -4737
- package/dist/hooks.js +59 -15
- package/dist/index.d.ts +10 -4
- package/dist/index.js +13 -7
- package/dist/integer.d.ts +11 -0
- package/dist/integer.js +11 -0
- package/dist/issue-path.d.ts +10 -0
- package/dist/issue-path.js +10 -0
- package/dist/local-load.d.ts +1 -1
- package/dist/local-load.js +4 -14
- package/dist/loopback.d.ts +26 -0
- package/dist/loopback.js +54 -0
- package/dist/migration-receipt.d.ts +42 -0
- package/dist/migration-receipt.js +12 -0
- package/dist/one-time-migrations.d.ts +62 -0
- package/dist/one-time-migrations.js +828 -0
- package/dist/prompts-digest.d.ts +1 -1
- package/dist/prompts-digest.js +3 -2
- package/dist/reader.d.ts +2 -2
- package/dist/remote-exec.d.ts +45 -187
- package/dist/remote-exec.js +16 -10
- package/dist/resolve-roster.d.ts +18 -3
- package/dist/resolve-roster.js +28 -25
- package/dist/retired-envs.d.ts +24 -0
- package/dist/retired-envs.js +114 -0
- package/dist/retired-form.d.ts +31 -0
- package/dist/retired-form.js +28 -0
- package/dist/safety-merge-spec.d.ts +131 -191
- package/dist/safety-merge-spec.js +18 -14
- package/dist/scheduler-lifetime.d.ts +5 -0
- package/dist/scheduler-lifetime.js +7 -0
- package/dist/scheduler-store-migration.d.ts +14 -0
- package/dist/scheduler-store-migration.js +14 -0
- package/dist/scheduler-store-node.d.ts +28 -12
- package/dist/scheduler-store-node.js +32 -23
- package/dist/scheduler-store.d.ts +47 -14
- package/dist/scheduler-store.js +32 -61
- package/dist/secret-refs.d.ts +3 -3
- package/dist/secret-refs.js +1 -1
- package/dist/secret-scan.d.ts +14 -24
- package/dist/secret-scan.js +45 -23
- package/dist/sha256-core.d.ts +16 -0
- package/dist/sha256-core.js +138 -0
- package/dist/sha256.d.ts +6 -1
- package/dist/sha256.js +8 -98
- package/dist/skills-manifest.js +1 -1
- package/dist/types.d.ts +1509 -13536
- package/dist/types.js +526 -438
- package/dist/url-shape.d.ts +34 -0
- package/dist/url-shape.js +61 -0
- package/dist/web-admin-credential.d.ts +96 -0
- package/dist/{center-credential.js → web-admin-credential.js} +49 -46
- package/dist/web-admin-env.d.ts +33 -0
- package/dist/web-admin-env.js +33 -0
- package/dist/worker-row-verdict.d.ts +16 -0
- package/dist/worker-row-verdict.js +31 -0
- package/dist/workers-rows.d.ts +34 -0
- package/dist/workers-rows.js +42 -0
- package/dist/zod-unwrap.d.ts +11 -0
- package/dist/zod-unwrap.js +25 -0
- package/package.json +17 -9
- package/conformance/cases/c46-s811-host-name-url-userinfo-characterization/meta.json +0 -6
- package/conformance/cases/c47-s811-roles-key-url-userinfo-characterization/meta.json +0 -6
- package/conformance/migrate-workers/m01-g5-k8s-env-lifted/expected.json +0 -49
- package/conformance/migrate-workers/m01-g5-k8s-env-lifted/input.json +0 -26
- package/conformance/migrate-workers/m01-g5-k8s-env-lifted/meta.json +0 -4
- package/conformance/migrate-workers/m02-g5-idempotent/expected.json +0 -38
- package/conformance/migrate-workers/m02-g5-idempotent/input.json +0 -33
- package/conformance/migrate-workers/m02-g5-idempotent/meta.json +0 -5
- package/conformance/migrate-workers/m03-g5-refused-no-lane/expected.json +0 -71
- package/conformance/migrate-workers/m03-g5-refused-no-lane/input.json +0 -42
- package/conformance/migrate-workers/m03-g5-refused-no-lane/meta.json +0 -4
- package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/expected.json +0 -52
- package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/input.json +0 -30
- package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/meta.json +0 -4
- package/conformance/migrate-workers/m05-row-verdict-reserved-env/expected.json +0 -82
- package/conformance/migrate-workers/m05-row-verdict-reserved-env/input.json +0 -68
- package/conformance/migrate-workers/m05-row-verdict-reserved-env/meta.json +0 -4
- package/dist/center-credential.d.ts +0 -116
- package/dist/issue-text.d.ts +0 -10
- package/dist/issue-text.js +0 -8
- package/dist/migrate-workers.d.ts +0 -71
- package/dist/migrate-workers.js +0 -351
- package/dist/migrate.d.ts +0 -255
- package/dist/migrate.js +0 -542
- /package/conformance/cases/{c46-s811-host-name-url-userinfo-characterization → c46-s811-host-name-url-userinfo-withheld}/input.json +0 -0
package/dist/hooks.js
CHANGED
|
@@ -29,9 +29,12 @@
|
|
|
29
29
|
* Pure zod contract — zero runtime deps beyond zod, browser-safe, same as the rest of this package.
|
|
30
30
|
*/
|
|
31
31
|
import { z } from "zod";
|
|
32
|
+
import { INTEGER } from "./integer.js";
|
|
32
33
|
// ── event set ──────────────────────────────────────────────────────────────────────────────────────────
|
|
34
|
+
// The two halves below are where each word came from (CC 2.1.198's own table, then the later additions) — provenance for the
|
|
35
|
+
// reader of this file, not a contract: they are module-private, and the ONE exported closed set is {@link HOOK_EVENTS}.
|
|
33
36
|
/** CC 2.1.198 full hook-event set (jP array) — 27 events. Order matches the shell's HOOK_EVENTS. */
|
|
34
|
-
|
|
37
|
+
const CC_198_HOOK_EVENTS = [
|
|
35
38
|
"PreToolUse",
|
|
36
39
|
"PostToolUse",
|
|
37
40
|
"PostToolUseFailure",
|
|
@@ -71,8 +74,8 @@ export const CC_198_HOOK_EVENTS = [
|
|
|
71
74
|
* (naming the missing words) whenever the CC anchor snapshot in `test/fixtures/cc-hook-events.json` holds an
|
|
72
75
|
* event this set does not, and that snapshot is produced by `scripts/extract-cc-hook-events.mjs`, never typed.
|
|
73
76
|
*/
|
|
74
|
-
|
|
75
|
-
/** The full 33-event contract set = CC 198's 27 + the 6 post-198 events. */
|
|
77
|
+
const POST_198_HOOK_EVENTS = ["CwdChanged", "FileChanged", "MessageDisplay", "DirectoryAdded", "PreModelSwitch", "PostModelSwitch"];
|
|
78
|
+
/** The full 33-event contract set = CC 198's 27 + the 6 post-198 events — the one exported closed set of hook event names. */
|
|
76
79
|
export const HOOK_EVENTS = [...CC_198_HOOK_EVENTS, ...POST_198_HOOK_EVENTS];
|
|
77
80
|
export const HookEventName = z.enum(HOOK_EVENTS);
|
|
78
81
|
// ── ownership (owner-single) ─────────────────────────────────────────────────────────────────────
|
|
@@ -100,8 +103,8 @@ export const ENGINE_OWNED_HOOK_EVENTS = [
|
|
|
100
103
|
export const HOOK_EVENT_OWNER = Object.fromEntries(HOOK_EVENTS.map((e) => [e, ENGINE_OWNED_HOOK_EVENTS.includes(e) ? "engine" : "shell"]));
|
|
101
104
|
/**
|
|
102
105
|
* Which INPUT FIELD an entry's `matcher` string is matched against, per event (`null` = matchers are
|
|
103
|
-
* ignored for the event; every entry matches). Ported from the shell's getMatchingHooks switch
|
|
104
|
-
*
|
|
106
|
+
* ignored for the event; every entry matches). Ported from the shell's getMatchingHooks switch. HOW the matcher is read
|
|
107
|
+
* against that field is {@link hookMatcherSelects} (the one reading).
|
|
105
108
|
*/
|
|
106
109
|
export const HOOK_EVENT_MATCHER_FIELD = {
|
|
107
110
|
PreToolUse: "tool_name",
|
|
@@ -201,20 +204,20 @@ export const BaseHookInput = z.object({
|
|
|
201
204
|
export const PreToolUseHookInput = BaseHookInput.extend({
|
|
202
205
|
hook_event_name: z.literal("PreToolUse"),
|
|
203
206
|
tool_name: z.string(),
|
|
204
|
-
tool_input: z.unknown(),
|
|
207
|
+
tool_input: z.unknown().optional(),
|
|
205
208
|
tool_use_id: z.string(),
|
|
206
209
|
});
|
|
207
210
|
export const PostToolUseHookInput = BaseHookInput.extend({
|
|
208
211
|
hook_event_name: z.literal("PostToolUse"),
|
|
209
212
|
tool_name: z.string(),
|
|
210
|
-
tool_input: z.unknown(),
|
|
211
|
-
tool_response: z.unknown(),
|
|
213
|
+
tool_input: z.unknown().optional(),
|
|
214
|
+
tool_response: z.unknown().optional(),
|
|
212
215
|
tool_use_id: z.string(),
|
|
213
216
|
});
|
|
214
217
|
export const PostToolUseFailureHookInput = BaseHookInput.extend({
|
|
215
218
|
hook_event_name: z.literal("PostToolUseFailure"),
|
|
216
219
|
tool_name: z.string(),
|
|
217
|
-
tool_input: z.unknown(),
|
|
220
|
+
tool_input: z.unknown().optional(),
|
|
218
221
|
tool_use_id: z.string(),
|
|
219
222
|
error: z.string(),
|
|
220
223
|
is_interrupt: z.boolean().optional(),
|
|
@@ -222,7 +225,7 @@ export const PostToolUseFailureHookInput = BaseHookInput.extend({
|
|
|
222
225
|
/** One resolved tool call inside a PostToolBatch payload. */
|
|
223
226
|
export const PostToolBatchToolCall = z.object({
|
|
224
227
|
tool_name: z.string(),
|
|
225
|
-
tool_input: z.unknown(),
|
|
228
|
+
tool_input: z.unknown().optional(),
|
|
226
229
|
tool_use_id: z.string(),
|
|
227
230
|
tool_response: z.unknown().optional(),
|
|
228
231
|
});
|
|
@@ -299,13 +302,13 @@ export const PostCompactHookInput = BaseHookInput.extend({
|
|
|
299
302
|
export const PermissionRequestHookInput = BaseHookInput.extend({
|
|
300
303
|
hook_event_name: z.literal("PermissionRequest"),
|
|
301
304
|
tool_name: z.string(),
|
|
302
|
-
tool_input: z.unknown(),
|
|
305
|
+
tool_input: z.unknown().optional(),
|
|
303
306
|
permission_suggestions: z.array(PermissionUpdate).optional(),
|
|
304
307
|
});
|
|
305
308
|
export const PermissionDeniedHookInput = BaseHookInput.extend({
|
|
306
309
|
hook_event_name: z.literal("PermissionDenied"),
|
|
307
310
|
tool_name: z.string(),
|
|
308
|
-
tool_input: z.unknown(),
|
|
311
|
+
tool_input: z.unknown().optional(),
|
|
309
312
|
tool_use_id: z.string(),
|
|
310
313
|
reason: z.string(),
|
|
311
314
|
});
|
|
@@ -396,7 +399,7 @@ export const MessageDisplayHookInput = BaseHookInput.extend({
|
|
|
396
399
|
/** Stable per-message UUID across flushes (not the API msg_… id). */
|
|
397
400
|
message_id: z.string(),
|
|
398
401
|
/** Zero-based flush index within the message. */
|
|
399
|
-
index:
|
|
402
|
+
index: INTEGER,
|
|
400
403
|
/** True on the message's last flush (exactly one per message). */
|
|
401
404
|
final: z.boolean(),
|
|
402
405
|
/** Newly completed lines since the prior flush (final flush may end mid-line / be empty). */
|
|
@@ -675,11 +678,52 @@ export const HttpHookEntry = z.object({
|
|
|
675
678
|
export const HookEntry = z.discriminatedUnion("type", [CommandHookEntry, PromptHookEntry, AgentHookEntry, HttpHookEntry]);
|
|
676
679
|
/** One matcher group: `matcher` (see HOOK_EVENT_MATCHER_FIELD) + the hooks it fires. */
|
|
677
680
|
export const HookMatcherEntry = z.object({
|
|
678
|
-
/**
|
|
681
|
+
/** Read by {@link hookMatcherSelects} — the one reading (name list or unanchored JS regex; empty/`*`/absent matches everything). */
|
|
679
682
|
matcher: z.string().optional(),
|
|
680
683
|
hooks: z.array(HookEntry),
|
|
681
684
|
});
|
|
682
|
-
|
|
685
|
+
/** The characters a matcher may consist of to be read as a NAME LIST rather than a regex. */
|
|
686
|
+
const HOOK_MATCHER_NAME_LIST = /^[a-zA-Z0-9_|, -]+$/;
|
|
687
|
+
/**
|
|
688
|
+
* Does `matcher` select `name`? —— **the one reading** of a hooks matcher (11.0.0). The shell and the server both ask this
|
|
689
|
+
* function; neither keeps a copy.
|
|
690
|
+
*
|
|
691
|
+
* **Rule: the reading does not depend on the event.** `|`, `,` and spaces are name-list syntax under every event key, and the event is
|
|
692
|
+
* not an input. Why: `matcher` is one field of one shape ({@link HookMatcherEntry}) under every event; a reading that changed with the
|
|
693
|
+
* event key would make one string select different names once moved between events, and every reader would need the event to read
|
|
694
|
+
* a matcher at all. CC (the reference corpus `cli291.js:241202`, `xen` / `h5`) reads `,` and spaces as list syntax only for the events in its `h5`
|
|
695
|
+
* set — of the matcher-bearing events, `StopFailure` and `FileChanged` stay on `|` alone there, so a matcher under those two that
|
|
696
|
+
* contains `,` or a space is a name list here and a regex there (write `|` to mean the same thing in both).
|
|
697
|
+
*
|
|
698
|
+
* · absent / `""` / `"*"` ⇒ selects everything;
|
|
699
|
+
* · only name characters, `|`, `,` and spaces ⇒ a NAME LIST: split on `|` / `,`, trim each part, drop empty parts, membership
|
|
700
|
+
* (case-sensitive; a space inside a word stays — `"Ba sh"` is one word);
|
|
701
|
+
* · anything else ⇒ the whole matcher is a JS regex tested **unanchored** (`Edi.` selects `Edit`, `MultiEdit`, `NotebookEdit`;
|
|
702
|
+
* write `^Edit$` to pin one name). A regex that does not compile ⇒ `"invalid"`: the caller does not run the hook and accounts
|
|
703
|
+
* for the bad matcher itself.
|
|
704
|
+
* Before 11.0.0 the server anchored the regex form (`^(?:…)$`) while the shell did not, so one regex matcher selected different
|
|
705
|
+
* tools in the two places. A deployment whose regex matchers relied on that anchoring selects MORE tools now — add `^…$`.
|
|
706
|
+
* Pure: no budget / timeout — a caller evaluating untrusted regex matchers under a deadline does so around this call.
|
|
707
|
+
*/
|
|
708
|
+
export function hookMatcherSelects(matcher, name) {
|
|
709
|
+
if (matcher === undefined || matcher === "" || matcher === "*")
|
|
710
|
+
return true;
|
|
711
|
+
if (HOOK_MATCHER_NAME_LIST.test(matcher)) {
|
|
712
|
+
return matcher
|
|
713
|
+
.split(/[|,]/)
|
|
714
|
+
.map((part) => part.trim())
|
|
715
|
+
.some((part) => part !== "" && part === name);
|
|
716
|
+
}
|
|
717
|
+
let pattern;
|
|
718
|
+
try {
|
|
719
|
+
pattern = new RegExp(matcher);
|
|
720
|
+
}
|
|
721
|
+
catch {
|
|
722
|
+
return "invalid";
|
|
723
|
+
}
|
|
724
|
+
return pattern.test(name);
|
|
725
|
+
}
|
|
726
|
+
export const HooksConfig = z.partialRecord(HookEventName, z.array(HookMatcherEntry));
|
|
683
727
|
/**
|
|
684
728
|
* DESIGN POINT ③ (slot semantics — RESERVED, core to finalize): how `spec.hooks` composes with the
|
|
685
729
|
* engine's own `deps.hooks` (e.g. the service's process-level toolTracer). "override" = the spec slot
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @sema-agent/settings-schema — the public barrel. ONE source of truth for the config contract shared by
|
|
3
|
-
*
|
|
3
|
+
* web-admin, the worker service, and the TOC desktop/CLI.
|
|
4
4
|
*/
|
|
5
5
|
export * from "./types.js";
|
|
6
6
|
export * from "./execution-lanes.js";
|
|
7
|
+
export * from "./url-shape.js";
|
|
8
|
+
export * from "./default-model.js";
|
|
9
|
+
export * from "./loopback.js";
|
|
7
10
|
export * from "./hash.js";
|
|
8
11
|
export * from "./sha256.js";
|
|
9
12
|
export * from "./skills-manifest.js";
|
|
@@ -18,9 +21,12 @@ export * from "./scheduler-store.js";
|
|
|
18
21
|
export * from "./cross-session.js";
|
|
19
22
|
export * from "./hooks.js";
|
|
20
23
|
export * from "./fleet.js";
|
|
21
|
-
export * from "./
|
|
22
|
-
export * from "./migrate.js";
|
|
24
|
+
export * from "./workers-rows.js";
|
|
23
25
|
export * from "./api/auth.js";
|
|
24
26
|
export * from "./api/auth-bridge.js";
|
|
25
27
|
export * from "./api/scopes.js";
|
|
26
|
-
export * from "./
|
|
28
|
+
export * from "./api/pull-token.js";
|
|
29
|
+
export * from "./api/feedback.js";
|
|
30
|
+
export * from "./web-admin-env.js";
|
|
31
|
+
export * from "./web-admin-credential.js";
|
|
32
|
+
export * from "./retired-envs.js";
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @sema-agent/settings-schema — the public barrel. ONE source of truth for the config contract shared by
|
|
3
|
-
*
|
|
3
|
+
* web-admin, the worker service, and the TOC desktop/CLI.
|
|
4
4
|
*/
|
|
5
5
|
export * from "./types.js";
|
|
6
6
|
export * from "./execution-lanes.js"; // 7.0.0 M-R2: the ONE lane / store vocabulary (EXECUTION_LANE_WORDS / EXECUTION_LANES / STORE_BACKENDS / SESSION_BACKENDS / MEMORY_ENGINE_BACKENDS) — pure data, browser-safe
|
|
7
|
+
export * from "./url-shape.js"; // 11.0.0: THE URL shape judge (httpUrlFlaws / httpUrlRule / isHierarchicalUrl), pure/browser-safe
|
|
8
|
+
export * from "./default-model.js"; // 11.0.0: THE catalog-default resolver (roles.default → active tier ladder → fallback), pure/browser-safe
|
|
9
|
+
export * from "./loopback.js"; // 11.0.0: the two「本机」predicates (auth relaxation — narrow / connection routing — wide), pure/browser-safe
|
|
7
10
|
export * from "./hash.js";
|
|
8
11
|
export * from "./sha256.js";
|
|
9
12
|
export * from "./skills-manifest.js";
|
|
@@ -18,13 +21,16 @@ export * from "./scheduler-store.js"; // R7 self-wake scheduler store CONTRACT (
|
|
|
18
21
|
export * from "./cross-session.js"; // CC-parity `settings.json` cross-session keys (crossSessionInbound / dialogExpiry) — pure/browser-safe
|
|
19
22
|
export * from "./hooks.js"; // CC-parity hooks contract (31-event set + owner map + per-event input/output shapes + HooksConfig) & stop attribution (stoppedBy) — pure/browser-safe
|
|
20
23
|
export * from "./fleet.js"; // scheduling/fleet contract (drain protocol · instance discovery · dispatch policy · quota lease · usage report · quota reset event) — CONTROL-PLANE-SCHEDULING-DESIGN, pure/browser-safe
|
|
21
|
-
export * from "./
|
|
22
|
-
export * from "./migrate.js"; // 0.5→0.6 migration tools (hosts grandfathering + worker.model→catalog migration PLAN — report/draft only, E1; EXPERT-REDESIGN §2-2/§3), pure/browser-safe
|
|
24
|
+
export * from "./workers-rows.js"; // 11.0.0 the workers domain's per-row verdict (readWorkersRows: a row that does not read is held, the rest read on) — permanent read semantics, pure
|
|
23
25
|
export * from "./api/auth.js"; // /api/v1/auth/* wire contract (RFC 8628 device flow + rotating refresh + logout + approve) — REGISTRY-REBUILD-DESIGN §2, M1 shipped shapes frozen, pure/browser-safe
|
|
24
|
-
export * from "./api/auth-bridge.js"; // 鉴权桥 contract: worker verifies
|
|
25
|
-
export * from "./api/scopes.js"; // multi-tenant scope contract: /api/v1/scopes* + /api/v1/auth/scope wire shapes + THE minting/switch decision functions (resolveTokenScope / canSwitchScope / effectiveScopeRole /
|
|
26
|
-
export * from "./
|
|
26
|
+
export * from "./api/auth-bridge.js"; // 鉴权桥 contract: worker verifies web-admin user JWT (RS256-only, JWKS kid-miss refresh + throttle, offline grace fail-closed) → VerifiedIdentity — design §5, the service verifier's spec
|
|
27
|
+
export * from "./api/scopes.js"; // multi-tenant scope contract: /api/v1/scopes* + /api/v1/auth/scope wire shapes + THE minting/switch decision functions (resolveTokenScope / canSwitchScope / effectiveScopeRole / readTokenScope) — web-admin imports these, never re-implements
|
|
28
|
+
export * from "./api/pull-token.js"; // scope-bound token FORM + minting rule (one rule, token families are data: WORKER_PULL_TOKEN) + claimed-binding reader + verifier (re-mint + constant-time compare), pure-JS HMAC-SHA256, browser-safe
|
|
29
|
+
export * from "./api/feedback.js"; // /bug report wire contract: FeedbackSubmitRequest (POST body) + FeedbackWire / FeedbackListResponse + the two caps, pure/browser-safe
|
|
30
|
+
export * from "./web-admin-env.js"; // WEB_ADMIN_ENV — every env name an engine reads to reach web-admin (one table; a leaf module), pure/browser-safe
|
|
31
|
+
export * from "./web-admin-credential.js"; // S-698 web-admin credential FILE contract: WebAdminCredentialEnvelope (user-session envelope, strict) + parseWebAdminCredentialFile (bare / envelope / unreadable — the one discrimination law) + judgeWebAdminCredentialDeclaration(env, credential) (pick-exactly-one over the credential's WEB_ADMIN_ENV pair; WEB_ADMIN_CREDENTIALS = access | assertion), pure/browser-safe
|
|
32
|
+
export * from "./retired-envs.js"; // the retired-env TOMBSTONE table (renamed / replaced / removed, closed set) + retiredEnvRefusal(env) (the one refusal sentence) + buildRetiredEnvWire() — engine boot, catalog wire, shell and web-admin read this one table, pure/browser-safe
|
|
27
33
|
// NOTE: the Node-fs-backed helpers (FileConfigStore + the file editor) are NOT in this barrel — they pull
|
|
28
34
|
// `node:fs`/`node:path` and would break a browser/client bundle that only wants the contract (e.g.
|
|
29
|
-
//
|
|
35
|
+
// web-admin's client components import the zod types through here). Import them from the Node-only
|
|
30
36
|
// subpath instead: `import { FileConfigStore } from "@sema-agent/settings-schema/node"`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The package's ONE integer rule (internal — not on any package subpath): `Number.isInteger` — a number with no fractional
|
|
3
|
+
* part, however large.
|
|
4
|
+
*
|
|
5
|
+
* The validator library's own integer check is narrower in its current major: it also refuses everything beyond
|
|
6
|
+
* ±(2^53 − 1). Every release of this package validated stored documents with the wider rule, and on a gate domain a stored
|
|
7
|
+
* value that stops reading is a whole-domain read failure, not a rejected write — so the rule stays where it always was and is
|
|
8
|
+
* written down here once, instead of being borrowed from the library and changing whenever the library does.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
export declare const INTEGER: z.ZodNumber;
|
package/dist/integer.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The package's ONE integer rule (internal — not on any package subpath): `Number.isInteger` — a number with no fractional
|
|
3
|
+
* part, however large.
|
|
4
|
+
*
|
|
5
|
+
* The validator library's own integer check is narrower in its current major: it also refuses everything beyond
|
|
6
|
+
* ±(2^53 − 1). Every release of this package validated stored documents with the wider rule, and on a gate domain a stored
|
|
7
|
+
* value that stops reading is a whole-domain read failure, not a rejected write — so the rule stays where it always was and is
|
|
8
|
+
* written down here once, instead of being borrowed from the library and changing whenever the library does.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
export const INTEGER = z.number().refine((n) => Number.isInteger(n), "Expected integer, received float");
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A zod issue's path as a {@link ConfigPath} (internal — not on any package subpath). zod types an issue path `PropertyKey[]`;
|
|
3
|
+
* this package's inputs are JSON (string keys, array indices), so a symbol segment never comes from a document — where one
|
|
4
|
+
* shows up anyway it leaves as its redacted `String()` form. The one place that converts the type, so the reports that name
|
|
5
|
+
* a field (`readWorkersRows`' `held[].field`, the one-time migrations' refusals) read it the same way.
|
|
6
|
+
*/
|
|
7
|
+
import { type ConfigPath } from "./config-fns.js";
|
|
8
|
+
export declare function issuePath(issue: {
|
|
9
|
+
readonly path: readonly PropertyKey[];
|
|
10
|
+
}): ConfigPath;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A zod issue's path as a {@link ConfigPath} (internal — not on any package subpath). zod types an issue path `PropertyKey[]`;
|
|
3
|
+
* this package's inputs are JSON (string keys, array indices), so a symbol segment never comes from a document — where one
|
|
4
|
+
* shows up anyway it leaves as its redacted `String()` form. The one place that converts the type, so the reports that name
|
|
5
|
+
* a field (`readWorkersRows`' `held[].field`, the one-time migrations' refusals) read it the same way.
|
|
6
|
+
*/
|
|
7
|
+
import { redactSecrets } from "./config-fns.js";
|
|
8
|
+
export function issuePath(issue) {
|
|
9
|
+
return issue.path.map((seg) => (typeof seg === "number" || typeof seg === "string" ? seg : redactSecrets(String(seg))));
|
|
10
|
+
}
|
package/dist/local-load.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare function remoteExecPath(root: string): string;
|
|
|
7
7
|
/** Read `<root>/config.d/remote-exec.json` → a VALIDATED RemoteExecSpec, or undefined if the file is absent
|
|
8
8
|
* (→ the engine defaults to `host` under CONFIG_PROVIDER=local). Throws (zod) on a present-but-invalid file. */
|
|
9
9
|
export declare function loadRemoteExec(root: string): Promise<RemoteExecSpec | undefined>;
|
|
10
|
-
/** Validate + ATOMICALLY write `<root>/config.d/remote-exec.json` (
|
|
10
|
+
/** Validate + ATOMICALLY write `<root>/config.d/remote-exec.json` (the package's one atomic writer, `./atomic-write`; never a half file). The
|
|
11
11
|
* client's `config` editor writes the exec backend through this; the engine reads it via loadRemoteExec. */
|
|
12
12
|
export declare function writeRemoteExec(root: string, spec: unknown): Promise<RemoteExecSpec>;
|
|
13
13
|
/** Parse `<root>/.env` (KEY=VALUE, `#` comments, optional surrounding quotes) MERGED OVER process.env (the
|
package/dist/local-load.js
CHANGED
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
* `<root>/config.d/remote-exec.json` (service vote), loaded/validated by loadRemoteExec — distinct from
|
|
8
8
|
* the per-domain `config.d/<domain>.json` the resolver reads. getEffective never reads it (not a DomainName).
|
|
9
9
|
*/
|
|
10
|
-
import { mkdir, readFile
|
|
10
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
import path from "node:path";
|
|
13
|
+
import { writeFileAtomic } from "./atomic-write.js";
|
|
13
14
|
import { FileConfigStore } from "./file-store.js";
|
|
14
15
|
import { listRequiredEnvNames } from "./file-edit.js";
|
|
15
16
|
import { sanitizeZodError } from "./config-fns.js";
|
|
@@ -28,9 +29,6 @@ function parseRemoteExec(raw) {
|
|
|
28
29
|
return r.data;
|
|
29
30
|
throw sanitizeZodError(r.error);
|
|
30
31
|
}
|
|
31
|
-
// Monotonic suffix so two atomic writes in the SAME process+millisecond can't collide on the tmp name (which
|
|
32
|
-
// would make one rename hit ENOENT / lose a write). pid+Date.now() alone isn't unique under concurrency.
|
|
33
|
-
let tmpSeq = 0;
|
|
34
32
|
/** The remoteExec file path under a config root (under config.d/, beside the per-domain files). */
|
|
35
33
|
export function remoteExecPath(root) {
|
|
36
34
|
return path.join(root, "config.d", "remote-exec.json");
|
|
@@ -62,21 +60,13 @@ export async function loadRemoteExec(root) {
|
|
|
62
60
|
}
|
|
63
61
|
return parseRemoteExec(json);
|
|
64
62
|
}
|
|
65
|
-
/** Validate + ATOMICALLY write `<root>/config.d/remote-exec.json` (
|
|
63
|
+
/** Validate + ATOMICALLY write `<root>/config.d/remote-exec.json` (the package's one atomic writer, `./atomic-write`; never a half file). The
|
|
66
64
|
* client's `config` editor writes the exec backend through this; the engine reads it via loadRemoteExec. */
|
|
67
65
|
export async function writeRemoteExec(root, spec) {
|
|
68
66
|
const parsed = parseRemoteExec(spec);
|
|
69
67
|
const dir = path.join(root, "config.d");
|
|
70
68
|
await mkdir(dir, { recursive: true });
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
await writeFile(tmp, JSON.stringify(parsed, null, 2) + "\n", "utf8");
|
|
74
|
-
await rename(tmp, remoteExecPath(root));
|
|
75
|
-
}
|
|
76
|
-
catch (e) {
|
|
77
|
-
await unlink(tmp).catch(() => { }); // never leave a half-written tmp behind
|
|
78
|
-
throw e;
|
|
79
|
-
}
|
|
69
|
+
writeFileAtomic(remoteExecPath(root), JSON.stringify(parsed, null, 2) + "\n", "config-document");
|
|
80
70
|
return parsed;
|
|
81
71
|
}
|
|
82
72
|
/** Resolve a `file:<path>` .env VALUE → the file's trimmed content (the file-NAME secret ref, config-research
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「这是本机吗」—— **两个**问题,各一只具名谓词(11.0.0)。读者按自己问的是哪一个来选,不再各写一份字面表。
|
|
3
|
+
*
|
|
4
|
+
* · **鉴权放宽**({@link isLoopbackAuthHost},窄):要不要因为对端是本机而少要一样东西(免登录、允许明文 http 带凭据)。
|
|
5
|
+
* 窄是安全方向 —— 认少了只会多要一次凭据;认多了就是把放宽送给一台不是本机的主机。只认字面。
|
|
6
|
+
* · **连接路由**({@link isLoopbackRouteHost},宽):这条连接会不会落在本机(要不要绕开代理直连)。宽是正确方向 ——
|
|
7
|
+
* 认少了,本机目标被送进代理,代理那头的 127.0.0.1 是代理自己。
|
|
8
|
+
*
|
|
9
|
+
* 两只都是纯函数,入参是 `URL.hostname`、socket 地址或裸主机名;不用 `node:net`(浏览器 / 客户端包可用)。
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* 鉴权放宽问的「本机」:只认四个字面 `127.0.0.1` / `localhost` / `::1` / `[::1]`(`URL.hostname` 对 IPv6 带方括号,两写法都收),
|
|
13
|
+
* 外加 socket 地址形 `::ffff:127.0.0.1`(双栈监听上 IPv4 回环连接的 `remoteAddress`)。大小写变体、尾点、127/8 的其它地址、
|
|
14
|
+
* 全写 IPv6、未指定地址一律不算 —— 那些都要先被「规范化」才是本机,而放宽不赌规范化。
|
|
15
|
+
*/
|
|
16
|
+
export declare function isLoopbackAuthHost(host: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* 连接路由问的「本机」(大小写不敏感):
|
|
19
|
+
* · `localhost`(含 FQDN 尾点 `localhost.`);
|
|
20
|
+
* · IPv4 `127.0.0.0/8` 整段与未指定地址 `0.0.0.0`(作为目的地址它在本机就是本机);
|
|
21
|
+
* · IPv6 `::1`(带不带方括号、全写都算)与未指定地址 `::`;
|
|
22
|
+
* · IPv4 映射 IPv6 的回环段 `::ffff:127.x.x.x` 与 `::ffff:0.0.0.0`(WHATWG 把它们规范成 `::ffff:7f00:1` 形,按规范形判)。
|
|
23
|
+
* 刻意**不**认 `*.localhost` 子域(能否落到本机取决于系统解析器,不是地址本身的事实)、带区域 id 的 IPv6、简写 IPv4(`127.1`)。
|
|
24
|
+
* 认不出的写法一律答 `false`(按远端处置)。
|
|
25
|
+
*/
|
|
26
|
+
export declare function isLoopbackRouteHost(host: string): boolean;
|
package/dist/loopback.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「这是本机吗」—— **两个**问题,各一只具名谓词(11.0.0)。读者按自己问的是哪一个来选,不再各写一份字面表。
|
|
3
|
+
*
|
|
4
|
+
* · **鉴权放宽**({@link isLoopbackAuthHost},窄):要不要因为对端是本机而少要一样东西(免登录、允许明文 http 带凭据)。
|
|
5
|
+
* 窄是安全方向 —— 认少了只会多要一次凭据;认多了就是把放宽送给一台不是本机的主机。只认字面。
|
|
6
|
+
* · **连接路由**({@link isLoopbackRouteHost},宽):这条连接会不会落在本机(要不要绕开代理直连)。宽是正确方向 ——
|
|
7
|
+
* 认少了,本机目标被送进代理,代理那头的 127.0.0.1 是代理自己。
|
|
8
|
+
*
|
|
9
|
+
* 两只都是纯函数,入参是 `URL.hostname`、socket 地址或裸主机名;不用 `node:net`(浏览器 / 客户端包可用)。
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* 鉴权放宽问的「本机」:只认四个字面 `127.0.0.1` / `localhost` / `::1` / `[::1]`(`URL.hostname` 对 IPv6 带方括号,两写法都收),
|
|
13
|
+
* 外加 socket 地址形 `::ffff:127.0.0.1`(双栈监听上 IPv4 回环连接的 `remoteAddress`)。大小写变体、尾点、127/8 的其它地址、
|
|
14
|
+
* 全写 IPv6、未指定地址一律不算 —— 那些都要先被「规范化」才是本机,而放宽不赌规范化。
|
|
15
|
+
*/
|
|
16
|
+
export function isLoopbackAuthHost(host) {
|
|
17
|
+
return host === "127.0.0.1" || host === "localhost" || host === "::1" || host === "[::1]" || host === "::ffff:127.0.0.1";
|
|
18
|
+
}
|
|
19
|
+
/** 点分十进制 IPv4(每段 0–255、无前导零)—— 与 Node `net.isIPv4` 同一个接受集。 */
|
|
20
|
+
const DOTTED_IPV4 = /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/;
|
|
21
|
+
/**
|
|
22
|
+
* 连接路由问的「本机」(大小写不敏感):
|
|
23
|
+
* · `localhost`(含 FQDN 尾点 `localhost.`);
|
|
24
|
+
* · IPv4 `127.0.0.0/8` 整段与未指定地址 `0.0.0.0`(作为目的地址它在本机就是本机);
|
|
25
|
+
* · IPv6 `::1`(带不带方括号、全写都算)与未指定地址 `::`;
|
|
26
|
+
* · IPv4 映射 IPv6 的回环段 `::ffff:127.x.x.x` 与 `::ffff:0.0.0.0`(WHATWG 把它们规范成 `::ffff:7f00:1` 形,按规范形判)。
|
|
27
|
+
* 刻意**不**认 `*.localhost` 子域(能否落到本机取决于系统解析器,不是地址本身的事实)、带区域 id 的 IPv6、简写 IPv4(`127.1`)。
|
|
28
|
+
* 认不出的写法一律答 `false`(按远端处置)。
|
|
29
|
+
*/
|
|
30
|
+
export function isLoopbackRouteHost(host) {
|
|
31
|
+
let h = host.trim().toLowerCase();
|
|
32
|
+
if (h.startsWith("[") && h.endsWith("]"))
|
|
33
|
+
h = h.slice(1, -1);
|
|
34
|
+
h = h.replace(/\.+$/, ""); // FQDN 尾点:`localhost.` / `127.0.0.1.` 与不带点的是同一个目的地
|
|
35
|
+
if (h === "localhost")
|
|
36
|
+
return true;
|
|
37
|
+
if (DOTTED_IPV4.test(h))
|
|
38
|
+
return h.startsWith("127.") || h === "0.0.0.0";
|
|
39
|
+
if (!h.includes(":"))
|
|
40
|
+
return false;
|
|
41
|
+
// IPv6:交给 WHATWG 规范化(全写 / 前导零 / 点分映射形收成同一种压缩写法)再比;解析不动(区域 id 等)⇒ 按远端处置。
|
|
42
|
+
const bracketed = `http://[${h}]/`;
|
|
43
|
+
if (!URL.canParse(bracketed))
|
|
44
|
+
return false;
|
|
45
|
+
const canon = new URL(bracketed).hostname.slice(1, -1);
|
|
46
|
+
if (canon === "::1" || canon === "::")
|
|
47
|
+
return true;
|
|
48
|
+
const mapped = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(canon);
|
|
49
|
+
if (mapped === null)
|
|
50
|
+
return false;
|
|
51
|
+
const hi = parseInt(mapped[1], 16);
|
|
52
|
+
const lo = parseInt(mapped[2], 16);
|
|
53
|
+
return hi >> 8 === 127 || (hi === 0 && lo === 0);
|
|
54
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 一次性迁移的**收据形**与两张闭集(11.0.0)—— 叶子模块(运行期零依赖;只有型导入),由 `./one-time-migrations` 再导出(不进主桶)。
|
|
3
|
+
* 单拆出来只为一件事:调度店的读口(`./scheduler-store`,轻、浏览器安全)要在告警里带收据,不该为一个型把整套域 schema 拉进来。
|
|
4
|
+
*/
|
|
5
|
+
import type { DomainName, RetiredDomainName } from "./types.js";
|
|
6
|
+
/** 本版登记的一次性**数据**迁移 id(闭集;每个 id 在 `ONE_TIME_MIGRATIONS` 登记表里恰一行)。收据只许这些 id —— 同表登记的 wire 删码位
|
|
7
|
+
* (`WIRE_RETIREMENT_IDS`,`./one-time-migrations`)不改任何存储形,铸不出收据,不在本集。 */
|
|
8
|
+
export declare const ONE_TIME_MIGRATION_IDS: readonly ["SS-M1", "SS-M2", "SS-M3", "SS-M4", "SS-M5", "SS-M6", "SS-M7", "SS-M9"];
|
|
9
|
+
export type OneTimeMigrationId = (typeof ONE_TIME_MIGRATION_IDS)[number];
|
|
10
|
+
/**
|
|
11
|
+
* 一条收据说迁移**对一个坐标做了什么**(闭集,每词一义):
|
|
12
|
+
* - `moved` — 值搬到新位(`to`),义不变;
|
|
13
|
+
* - `rewritten` — 同一坐标上的值换成今天的生效读法(例:URL 剥掉从不上线的 fragment、调度行的 durable 键重铸、6.x 的 worker 行换新形);
|
|
14
|
+
* - `dropped-shadowed` — 删掉;它从来没生效过,因为另一个位赢了(例:`governance` 已设时 `runtime` 上的治理旧键、`sealedApiKey` 在场时的 `apiKeyEnv`);
|
|
15
|
+
* - `dropped-inert` — 删掉;今天的读法本就不让它生效(例:超界的主机条目、引擎从不读的旧字段、空的retired 域文档);
|
|
16
|
+
* - `refused` — 不改:要改就得替运维猜(或旧文档今天本就读不进);原样留着,读侧照旧响亮拒,`reason` 说为什么。
|
|
17
|
+
*/
|
|
18
|
+
export declare const MIGRATION_APPLIED_AS: readonly ["moved", "rewritten", "dropped-shadowed", "dropped-inert", "refused"];
|
|
19
|
+
export type MigrationAppliedAs = (typeof MIGRATION_APPLIED_AS)[number];
|
|
20
|
+
/** 收据指向的那份文档:配置域名、retired 域名(`runtime`),或调度店(`scheduler-store`)。 */
|
|
21
|
+
export type MigrationDocument = DomainName | RetiredDomainName | "scheduler-store";
|
|
22
|
+
/** 文档里的段坐标(字符串段 = 对象键,数字段 = 数组下标;与告警坐标同一形)。 */
|
|
23
|
+
export type MigrationPath = readonly (string | number)[];
|
|
24
|
+
interface ReceiptBase {
|
|
25
|
+
readonly migration: OneTimeMigrationId;
|
|
26
|
+
readonly document: MigrationDocument;
|
|
27
|
+
readonly path: MigrationPath;
|
|
28
|
+
}
|
|
29
|
+
/** 一条迁移收据。只点名坐标与处置,**不带值**(值可能是粘错位置的凭据)。 */
|
|
30
|
+
export type MigrationReceipt = (ReceiptBase & {
|
|
31
|
+
readonly appliedAs: "moved";
|
|
32
|
+
readonly to: {
|
|
33
|
+
readonly document: MigrationDocument;
|
|
34
|
+
readonly path: MigrationPath;
|
|
35
|
+
};
|
|
36
|
+
}) | (ReceiptBase & {
|
|
37
|
+
readonly appliedAs: "rewritten" | "dropped-shadowed" | "dropped-inert";
|
|
38
|
+
}) | (ReceiptBase & {
|
|
39
|
+
readonly appliedAs: "refused";
|
|
40
|
+
readonly reason: string;
|
|
41
|
+
});
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** 本版登记的一次性**数据**迁移 id(闭集;每个 id 在 `ONE_TIME_MIGRATIONS` 登记表里恰一行)。收据只许这些 id —— 同表登记的 wire 删码位
|
|
2
|
+
* (`WIRE_RETIREMENT_IDS`,`./one-time-migrations`)不改任何存储形,铸不出收据,不在本集。 */
|
|
3
|
+
export const ONE_TIME_MIGRATION_IDS = ["SS-M1", "SS-M2", "SS-M3", "SS-M4", "SS-M5", "SS-M6", "SS-M7", "SS-M9"];
|
|
4
|
+
/**
|
|
5
|
+
* 一条收据说迁移**对一个坐标做了什么**(闭集,每词一义):
|
|
6
|
+
* - `moved` — 值搬到新位(`to`),义不变;
|
|
7
|
+
* - `rewritten` — 同一坐标上的值换成今天的生效读法(例:URL 剥掉从不上线的 fragment、调度行的 durable 键重铸、6.x 的 worker 行换新形);
|
|
8
|
+
* - `dropped-shadowed` — 删掉;它从来没生效过,因为另一个位赢了(例:`governance` 已设时 `runtime` 上的治理旧键、`sealedApiKey` 在场时的 `apiKeyEnv`);
|
|
9
|
+
* - `dropped-inert` — 删掉;今天的读法本就不让它生效(例:超界的主机条目、引擎从不读的旧字段、空的retired 域文档);
|
|
10
|
+
* - `refused` — 不改:要改就得替运维猜(或旧文档今天本就读不进);原样留着,读侧照旧响亮拒,`reason` 说为什么。
|
|
11
|
+
*/
|
|
12
|
+
export const MIGRATION_APPLIED_AS = ["moved", "rewritten", "dropped-shadowed", "dropped-inert", "refused"];
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { MigrationReceipt, OneTimeMigrationId } from "./migration-receipt.js";
|
|
2
|
+
import { type DomainName, type RetiredDomainName } from "./types.js";
|
|
3
|
+
export { MIGRATION_APPLIED_AS, ONE_TIME_MIGRATION_IDS, type MigrationAppliedAs, type MigrationDocument, type MigrationPath, type MigrationReceipt, type OneTimeMigrationId } from "./migration-receipt.js";
|
|
4
|
+
export { migrateSchedulerRecords } from "./scheduler-store-migration.js";
|
|
5
|
+
/** wire 删码位的 id(闭集;`W` = wire):没有存储形要改写、没有收据,与数据迁移同表登记只为让「什么时候删、删什么、删后谁接住」只写一处。 */
|
|
6
|
+
export declare const WIRE_RETIREMENT_IDS: readonly ["SS-W1"];
|
|
7
|
+
export type WireRetirementId = (typeof WIRE_RETIREMENT_IDS)[number];
|
|
8
|
+
/** 一条一次性迁移的窗(登记表的一行;纯数据)。 */
|
|
9
|
+
export interface OneTimeMigrationWindow {
|
|
10
|
+
/** 数据迁移 id(闭集 `ONE_TIME_MIGRATION_IDS`)或 wire 删码位 id(闭集 {@link WIRE_RETIREMENT_IDS});两集合起来每个 id 恰一行。 */
|
|
11
|
+
readonly id: OneTimeMigrationId | WireRetirementId;
|
|
12
|
+
/** 旧形在读侧的待遇(闭集,每词一义;「读写两面遇旧形一律响亮拒,拒句点名迁移 id」这条律的例外只在这一格里写):
|
|
13
|
+
* · `refused` — 读写两面拒,拒句点名本行 id(经 `migrationSignpost` 铸;钉:每个 `refused` 行的 id 在 `src/` 至少一处铸点,
|
|
14
|
+
* 且非 `refused` 行零铸点);
|
|
15
|
+
* · `rewritten-on-read` — 读时改写、不拒(SS-M3:调度店的下一个写者落盘),没有拒句可点名;
|
|
16
|
+
* · `not-stored` — 没有存储形(wire 删码位),谈不上拒。 */
|
|
17
|
+
readonly oldForm: "refused" | "rewritten-on-read" | "not-stored";
|
|
18
|
+
/** 引入这条迁移的版本。 */
|
|
19
|
+
readonly introducedIn: string;
|
|
20
|
+
/** 该版本在 npm 上的发布日(UTC 日历日 YYYY-MM-DD)。`null` = 未发布形,由抬 `package.json` 到 `introducedIn` 的发布准备提交回填。 */
|
|
21
|
+
readonly releasedOn: string | null;
|
|
22
|
+
/** = `releasedOn` + 30 天(UTC 日历日);与 `releasedOn` 同为 `null` 或同为日期。今天晚于它 ⇒ 到期门红。 */
|
|
23
|
+
readonly removableAfter: string | null;
|
|
24
|
+
/** 迁什么:旧形 → 新形(= 迁移前读路径上的生效读法)。 */
|
|
25
|
+
readonly rewrites: string;
|
|
26
|
+
/** 删码时删什么(到期门的红句逐字引用)。 */
|
|
27
|
+
readonly removal: string;
|
|
28
|
+
/** 删码之后,存量若还带着迁移前的形,由哪一条**既有**响亮臂接住;没有就如实写没有。 */
|
|
29
|
+
readonly afterRemoval: string;
|
|
30
|
+
}
|
|
31
|
+
/** 一次性迁移登记表 —— 本族各条窗的**唯一属主**。别处只写「窗见 `ONE_TIME_MIGRATIONS` 登记表」。 */
|
|
32
|
+
export declare const ONE_TIME_MIGRATIONS: readonly OneTimeMigrationWindow[];
|
|
33
|
+
/** 一组存储文档是不是**一个 scope 的全集**:`"scope"` = 缺席的域就是从未设过;`"partial"` = 缺席的域只是没给(principal 层、回滚史的
|
|
34
|
+
* 单域行、任意子集)。只有 SS-M1 读它。 */
|
|
35
|
+
export type DocumentCoverage = "scope" | "partial";
|
|
36
|
+
/** 一组存储文档(域名 / retired 域名 → 文档)。别的键原样带过、不动。 */
|
|
37
|
+
export type StoredDocuments = Readonly<Partial<Record<DomainName | RetiredDomainName, unknown>>>;
|
|
38
|
+
export interface StoredDocumentsMigration {
|
|
39
|
+
/** 迁移后的文档集:没改的文档是**同一引用**;被移除的(retired 域)不在;新建的(例:迁出的 `governance` / `limits`)在。 */
|
|
40
|
+
readonly docs: Readonly<Record<string, unknown>>;
|
|
41
|
+
/** 逐条收据(步序 SS-M1 → SS-M2 → SS-M5 → SS-M6 → SS-M9 → SS-M7 → SS-M4:纯改写步在前,用新 schema 终判的 SS-M4 最后;步内按坐标)。
|
|
42
|
+
* 只有 `refused` 的收据 = 什么都没改。 */
|
|
43
|
+
readonly receipts: readonly MigrationReceipt[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 迁移一组存储文档(见文件头「入口」)。纯函数;没改的文档原样返回;**不抬任何版本号**(结果里没有版本 —— 那是调用方的)。
|
|
47
|
+
* 重跑恒等:第二次跑零改动,只剩第一次就 `refused` 的那几张收据(那些坐标原样留着,读侧照旧拒)。
|
|
48
|
+
*/
|
|
49
|
+
export declare function migrateStoredDocuments(docs: StoredDocuments, opts: {
|
|
50
|
+
readonly coverage: DocumentCoverage;
|
|
51
|
+
}): StoredDocumentsMigration;
|
|
52
|
+
/**
|
|
53
|
+
* 迁移一份冻结的 effective(见文件头「入口」):域键过与 {@link migrateStoredDocuments} 同一组步(coverage `"scope"` —— effective 里每个域
|
|
54
|
+
* 都物化了),其余键(`version` / `updatedAt` / wire 上的 `skills` 清单形 …)原样。键序保持;被移除的retired 域不在;effective 没改 ⇒ 同一引用。
|
|
55
|
+
* 不是对象 ⇒ 原样返回(判形是读者的事)。
|
|
56
|
+
*/
|
|
57
|
+
export declare function migrateEffectiveSnapshot(effective: unknown): {
|
|
58
|
+
readonly effective: unknown;
|
|
59
|
+
readonly receipts: readonly MigrationReceipt[];
|
|
60
|
+
};
|
|
61
|
+
/** 本包域 schema 里全部 URL 座位的坐标模式(派生;数组 / Record 位写 `*`)—— 迁移不用它,它给钉与说明看「今天派生出哪些座位」。 */
|
|
62
|
+
export declare function urlSeatPatterns(): string[];
|