@jini-ai/core 0.6.21 → 0.6.23
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 +10 -0
- package/dist/approval.d.ts +15 -0
- package/dist/approval.js +20 -6
- package/dist/gated-mutations/gateway.d.ts +1 -0
- package/dist/gated-mutations/gateway.js +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/redact.d.ts +32 -5
- package/dist/redact.js +575 -165
- package/dist/teardown.d.ts +30 -0
- package/dist/teardown.js +43 -0
- package/dist/tool-input-envelope.d.ts +20 -0
- package/dist/tool-input-envelope.js +40 -0
- package/dist/tool-input-normalization.js +2 -0
- package/dist/user-facing-error.d.ts +34 -0
- package/dist/user-facing-error.js +42 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
## 0.6.23
|
|
2
|
+
|
|
3
|
+
- Security hardening.
|
|
4
|
+
|
|
1
5
|
# @jini-ai/core
|
|
2
6
|
|
|
7
|
+
## 0.6.22
|
|
8
|
+
|
|
9
|
+
- `UserFacingError` and `formatUserFacingError`; `decodeToolInputObject` and `unwrapToolInputEnvelope` for delegated tool input.
|
|
10
|
+
- Redaction: whole PEM blocks, merged spans, desktop id and path masking; an unquoted URL secret parameter keeps its enclosing quote.
|
|
11
|
+
- `PlanStaleError` carries `code: "PLAN_STALE"`.
|
|
12
|
+
|
|
3
13
|
## 0.6.21
|
|
4
14
|
|
|
5
15
|
- `createPreparedBatchHandler`: prepares a complete direct batch before any effect, reusing the approval handler's input snapshot, cap, duplicate detection and cancellation lifecycle, with no review card.
|
package/dist/approval.d.ts
CHANGED
|
@@ -35,6 +35,17 @@ export interface RememberedApprovalPort {
|
|
|
35
35
|
confirmer: HumanConfirmer;
|
|
36
36
|
}): Promise<void>;
|
|
37
37
|
}
|
|
38
|
+
/** Host-owned view/version snapshot captured before asking, then carried into the approved
|
|
39
|
+
* effect. The host validates it at the effect boundary; this port grants no authorization. */
|
|
40
|
+
export interface ApprovalContextPort {
|
|
41
|
+
capture(required: {
|
|
42
|
+
ctx: ToolExecutionContext;
|
|
43
|
+
}): Promise<unknown>;
|
|
44
|
+
prepare(required: {
|
|
45
|
+
ctx: ToolExecutionContext;
|
|
46
|
+
snapshot: unknown;
|
|
47
|
+
}): ToolExecutionContext;
|
|
48
|
+
}
|
|
38
49
|
export interface ApprovalSteps<TPrepared, TDescription> {
|
|
39
50
|
prepare(required: {
|
|
40
51
|
ctx: ToolExecutionContext;
|
|
@@ -153,7 +164,10 @@ export declare function createApprovalProposalStore<TDescription>({ responseTool
|
|
|
153
164
|
};
|
|
154
165
|
/** Apply a host classification through the same handler owner used by domain plans.
|
|
155
166
|
* A host description's string `rememberKey` opts into reusable grants; descriptions remain opaque.
|
|
167
|
+
* Optional context is captured only for asking actions and prepared only after approval.
|
|
156
168
|
* @returns The registration with one approval handler; authorization policy is preserved.
|
|
169
|
+
* @complexity O(input bytes) snapshot plus bounded injected ports; no retained cross-call state.
|
|
170
|
+
* @overallScore 100
|
|
157
171
|
*/
|
|
158
172
|
export declare function applyApprovalPolicy<TDescription>({ registration, classify, asks, describe, askHuman, notConfirmed }: {
|
|
159
173
|
registration: ToolRegistration;
|
|
@@ -171,5 +185,6 @@ export declare function applyApprovalPolicy<TDescription>({ registration, classi
|
|
|
171
185
|
notConfirmed: ApprovalSteps<string, TDescription>['notConfirmed'];
|
|
172
186
|
}, optional?: {
|
|
173
187
|
remembered?: RememberedApprovalPort;
|
|
188
|
+
context?: ApprovalContextPort;
|
|
174
189
|
}): ToolRegistration;
|
|
175
190
|
//# sourceMappingURL=approval.d.ts.map
|
package/dist/approval.js
CHANGED
|
@@ -249,20 +249,34 @@ export function createApprovalProposalStore({ responseTool, messages }, { create
|
|
|
249
249
|
}
|
|
250
250
|
/** Apply a host classification through the same handler owner used by domain plans.
|
|
251
251
|
* A host description's string `rememberKey` opts into reusable grants; descriptions remain opaque.
|
|
252
|
+
* Optional context is captured only for asking actions and prepared only after approval.
|
|
252
253
|
* @returns The registration with one approval handler; authorization policy is preserved.
|
|
254
|
+
* @complexity O(input bytes) snapshot plus bounded injected ports; no retained cross-call state.
|
|
255
|
+
* @overallScore 100
|
|
253
256
|
*/
|
|
254
257
|
export function applyApprovalPolicy({ registration, classify, asks, describe, askHuman, notConfirmed }, optional = {}) {
|
|
255
258
|
return { ...registration, handler: createApprovalHandler({
|
|
256
|
-
prepare: async ({ ctx }) =>
|
|
259
|
+
prepare: async ({ ctx }) => {
|
|
260
|
+
const actionClass = classify({ input: ctx.input });
|
|
261
|
+
const ask = asks({ class: actionClass });
|
|
262
|
+
if (!ask || !optional.context)
|
|
263
|
+
return { actionClass, ask };
|
|
264
|
+
return { actionClass, ask, snapshot: await optional.context.capture({ ctx }) };
|
|
265
|
+
},
|
|
257
266
|
describe: async ({ ctx, prepared }) => {
|
|
258
|
-
const
|
|
259
|
-
const description = await describe({ ctx, class: prepared });
|
|
267
|
+
const description = await describe({ ctx, class: prepared.actionClass });
|
|
260
268
|
const candidate = { value: description };
|
|
261
|
-
return { ask, description, ...(isNonArrayRecord(candidate) && typeof candidate.value.rememberKey === 'string'
|
|
269
|
+
return { ask: prepared.ask, description, ...(isNonArrayRecord(candidate) && typeof candidate.value.rememberKey === 'string'
|
|
262
270
|
? { rememberKey: candidate.value.rememberKey } : {}) };
|
|
263
271
|
},
|
|
264
|
-
askHuman,
|
|
265
|
-
|
|
272
|
+
askHuman,
|
|
273
|
+
notConfirmed: ({ reason, prepared }) => notConfirmed({ reason, prepared: prepared?.actionClass }),
|
|
274
|
+
run: ({ ctx, prepared }, options) => {
|
|
275
|
+
if (!prepared.ask || !optional.context)
|
|
276
|
+
return registration.handler(ctx, options);
|
|
277
|
+
const executionContext = optional.context.prepare({ ctx, snapshot: prepared.snapshot });
|
|
278
|
+
return registration.handler(executionContext, options);
|
|
279
|
+
},
|
|
266
280
|
}, optional) };
|
|
267
281
|
}
|
|
268
282
|
//# sourceMappingURL=approval.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export { createDaemon } from './daemon.js';
|
|
|
7
7
|
export type { PackDisposalFailure } from './pack-lifecycle.js';
|
|
8
8
|
export { disposePacks, registerPackTools } from './pack-lifecycle.js';
|
|
9
9
|
export * from './redact.js';
|
|
10
|
+
export * from './user-facing-error.js';
|
|
11
|
+
export { onTeardown, runTeardownSteps, type TeardownHost, type TeardownStep } from './teardown.js';
|
|
10
12
|
export * from './api-token-auth.js';
|
|
11
13
|
export * from './origin-validation.js';
|
|
12
14
|
export * from './principal.js';
|
|
@@ -30,6 +32,7 @@ export * from "./native-regexp.js";
|
|
|
30
32
|
export { ForbiddenError as ToolPermissionDeniedError, requireToolPermission, adaptLegacyAuthorize, type LegacyToolAuthorizeFn, type AuthorizationPort as ToolPermissionAuthorizationPort, type RequireToolPermissionRequired, type RequireToolPermissionOptional, } from "./tool-permissions.js";
|
|
31
33
|
export { evaluateFeatureFlag, type FeatureFlagDecision } from './feature-flags.js';
|
|
32
34
|
export { normalizeToolInput, withNormalizationNotes, ToolInputNormalizationError, type NormalizedToolInput, type ToolInputNormalizer } from './tool-input-normalization.js';
|
|
35
|
+
export { decodeToolInputObject, unwrapToolInputEnvelope } from './tool-input-envelope.js';
|
|
33
36
|
export { applyBatchInputs, BATCH_GUIDANCE_MARKER, withoutBatchGuidance, batchOutcomeFor, batchDescriptorFor, batchItemRequiredFields, batchEligibilityFor, defaultBatchableTools, withBatchInput, DEFAULT_MAX_BATCH_ITEMS, type BatchableTool, type BatchEligibility, type BatchOptOut, type BatchResult, type BatchItemResult } from './batch-tool-inputs.js';
|
|
34
37
|
export type { MediaProviderCatalogPolicy, MediaProviderOption, ProviderPreset, ProviderPresetKind } from './provider-catalog.js';
|
|
35
38
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,8 @@ export * from './bindings.js';
|
|
|
5
5
|
export { createDaemon } from './daemon.js';
|
|
6
6
|
export { disposePacks, registerPackTools } from './pack-lifecycle.js';
|
|
7
7
|
export * from './redact.js';
|
|
8
|
+
export * from './user-facing-error.js';
|
|
9
|
+
export { onTeardown, runTeardownSteps } from './teardown.js';
|
|
8
10
|
export * from './api-token-auth.js';
|
|
9
11
|
export * from './origin-validation.js';
|
|
10
12
|
export * from './principal.js';
|
|
@@ -25,5 +27,6 @@ export * from "./native-regexp.js";
|
|
|
25
27
|
export { ForbiddenError as ToolPermissionDeniedError, requireToolPermission, adaptLegacyAuthorize, } from "./tool-permissions.js";
|
|
26
28
|
export { evaluateFeatureFlag } from './feature-flags.js';
|
|
27
29
|
export { normalizeToolInput, withNormalizationNotes, ToolInputNormalizationError } from './tool-input-normalization.js';
|
|
30
|
+
export { decodeToolInputObject, unwrapToolInputEnvelope } from './tool-input-envelope.js';
|
|
28
31
|
export { applyBatchInputs, BATCH_GUIDANCE_MARKER, withoutBatchGuidance, batchOutcomeFor, batchDescriptorFor, batchItemRequiredFields, batchEligibilityFor, defaultBatchableTools, withBatchInput, DEFAULT_MAX_BATCH_ITEMS } from './batch-tool-inputs.js';
|
|
29
32
|
//# sourceMappingURL=index.js.map
|
package/dist/redact.d.ts
CHANGED
|
@@ -38,6 +38,21 @@ export interface SecretShapePattern {
|
|
|
38
38
|
}
|
|
39
39
|
export declare const PEM_PATTERN_NAME = "PEM private key block";
|
|
40
40
|
export declare const SECRET_SHAPE_PATTERNS: readonly SecretShapePattern[];
|
|
41
|
+
/**
|
|
42
|
+
* Suppress PEM bodies across complete, ordered text lines before other redactors run.
|
|
43
|
+
* @param _required No ambient state; create one instance per framed output stream.
|
|
44
|
+
* @param _options Reserved optional policy inputs.
|
|
45
|
+
* @returns A line redactor and an EOF reset. Call reset after flushing the final line so a
|
|
46
|
+
* replacement child cannot inherit an unterminated block. Does not frame raw chunks or do I/O.
|
|
47
|
+
* @complexity O(n) per line; O(h) retained state for the open header's key type of length h.
|
|
48
|
+
* @example const keys = createPrivateKeyLineRedactor({}, {}); keys.redact({ text: line }, {});
|
|
49
|
+
*/
|
|
50
|
+
export declare function createPrivateKeyLineRedactor(_required: Record<string, never>, _options?: {}): {
|
|
51
|
+
redact(required: {
|
|
52
|
+
text: string;
|
|
53
|
+
}, optional?: Record<string, never>): string;
|
|
54
|
+
reset(required: Record<string, never>, optional?: Record<string, never>): void;
|
|
55
|
+
};
|
|
41
56
|
export declare const AGENT_FAILURE_SECRET_SHAPE_RE: RegExp;
|
|
42
57
|
/**
|
|
43
58
|
* Exact path SEGMENT names refused at any depth, matched case-insensitively against each segment
|
|
@@ -69,6 +84,8 @@ export interface SecretRedactionPattern {
|
|
|
69
84
|
name: string;
|
|
70
85
|
regex: RegExp;
|
|
71
86
|
}
|
|
87
|
+
/** Every marker redact can generate from its built-in categories; consumers normalize only these. */
|
|
88
|
+
export declare const GENERATED_MARKER_RE: RegExp;
|
|
72
89
|
/** Optional caller-owned secrets and named lexical rules, without ambient credential lookup. */
|
|
73
90
|
export interface SecretRedactionOptions {
|
|
74
91
|
/** Diagnostic text can retain addresses/numbers while using the same credential rules. Default true. */
|
|
@@ -88,9 +105,11 @@ export declare const NON_SECRET_TOKEN_RE: RegExp;
|
|
|
88
105
|
/**
|
|
89
106
|
* Returns `input` with every recognised secret / PII pattern replaced by a
|
|
90
107
|
* `[REDACTED:<kind>]` marker. Under the default policies, idempotent — re-running on already redacted
|
|
91
|
-
* text only matches new tokens.
|
|
108
|
+
* text only matches new tokens. Exact occurrences wholly within credential labels or generated markers preserve that syntax;
|
|
109
|
+
* crossing occurrences still mask their complete range; all value rules still see the original context. Defaults to conservative; `{ policy: 'aggressive' }`
|
|
92
110
|
* additionally masks bare 20+ character opaque runs. Exact secrets and extra patterns
|
|
93
|
-
* are honored under either heuristic policy.
|
|
111
|
+
* are honored under either heuristic policy.
|
|
112
|
+
* Exact-only replaces only supplied secrets in one pass,
|
|
94
113
|
* preserves unmatched characters, and inserts the optional literal marker without reprocessing it.
|
|
95
114
|
*
|
|
96
115
|
* Empty / non-string input passes through unchanged so the caller can use
|
|
@@ -117,9 +136,17 @@ export declare function formatErrorForLog(required: {
|
|
|
117
136
|
* caller can attach an audit summary to the trace metadata ('we stripped 2
|
|
118
137
|
* keys + 1 email before send').
|
|
119
138
|
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
139
|
+
* Every rule matches the ORIGINAL input and contributes value spans; overlapping or adjacent
|
|
140
|
+
* spans merge, and one left-to-right pass writes one marker per merged span. Sequential
|
|
141
|
+
* substitution passes leaked in every order tried: each pass saw text an earlier pass had
|
|
142
|
+
* changed. Exact secrets run first split labels (`a` inside `password=hunter2` left `hunter2`) and
|
|
143
|
+
* lost context (`note password=` left `hunter2`); run last, a lexical rule that stopped partway
|
|
144
|
+
* (the label rule at whitespace, vendor/query rules at `.`, `;`, `&`, `!` or quotes) left the rest
|
|
145
|
+
* of a known secret visible; protecting spans exempted secrets overlapping a marker; and
|
|
146
|
+
* overlapping secrets left a tail behind. Opt-in aggressive opaque
|
|
147
|
+
* rules are collected before PII rules so a numeric token keeps the opaque category when tied.
|
|
148
|
+
* @complexity O(n·(r + e) + s + k) for n input chars, r rules, e exact-secret needles, s needle
|
|
149
|
+
* chars and k spans.
|
|
123
150
|
*/
|
|
124
151
|
export declare function redactSecretsWithCounts({ input }: {
|
|
125
152
|
input: string;
|