@sema-agent/client-core 0.90.0 → 0.92.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 +365 -0
- package/README.md +48 -32
- package/dist/adapt/arms.js +13 -12
- package/dist/adapt/panelTasks.d.ts +0 -2
- package/dist/adapt/panelTasks.js +6 -26
- package/dist/adapt.js +2 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
- package/dist/adapter/activeRunSelfHeal.js +5 -27
- package/dist/adapter/downstream/eventToSdkMessage.js +4 -2
- package/dist/adapter/downstream/terminalToSdkResult.js +16 -7
- package/dist/adapter/downstream/wiringManifestView.d.ts +6 -0
- package/dist/adapter/downstream/wiringManifestView.js +16 -0
- package/dist/adapter/runStream.js +39 -20
- package/dist/askSurvivesStandingAnswer.d.ts +13 -0
- package/dist/askSurvivesStandingAnswer.js +53 -0
- package/dist/attachmentSeatCapability.d.ts +11 -0
- package/dist/attachmentSeatCapability.js +27 -0
- package/dist/attachmentsWireCaps.d.ts +9 -0
- package/dist/attachmentsWireCaps.js +74 -21
- package/dist/autoModeUnavailable.js +3 -2
- package/dist/cloudConfigWireCaps.js +5 -4
- package/dist/compensations.js +13 -17
- package/dist/controlRouter.d.ts +32 -25
- package/dist/controlRouter.js +166 -63
- package/dist/coreValuePorts.d.ts +4 -2
- package/dist/coreValuePorts.js +5 -0
- package/dist/decideFailureNote.js +7 -3
- package/dist/decideReceipt.d.ts +9 -0
- package/dist/decideReceipt.js +62 -1
- package/dist/disableSkillsWire.d.ts +1 -0
- package/dist/disableSkillsWire.js +8 -1
- package/dist/displayUntrusted.js +155 -5
- package/dist/effectiveFacts.d.ts +14 -4
- package/dist/effectiveFacts.js +45 -5
- package/dist/engineAgentAbsence.js +2 -1
- package/dist/engineCapReader.js +16 -10
- package/dist/engineCapsCache.d.ts +5 -1
- package/dist/engineCapsCache.js +69 -8
- package/dist/engineClosedSets.d.ts +2 -0
- package/dist/engineClosedSets.js +3 -0
- package/dist/engineErrorCodes.d.ts +17 -0
- package/dist/engineErrorCodes.js +47 -0
- package/dist/engineNoticeCodes.d.ts +14 -0
- package/dist/engineNoticeCodes.js +71 -0
- package/dist/executionLaneCapability.js +2 -0
- package/dist/gateOutcome.js +2 -17
- package/dist/gateVocabulary.d.ts +2 -4
- package/dist/gateVocabulary.js +3 -11
- package/dist/generated/engineFactTables.d.ts +27 -0
- package/dist/generated/engineFactTables.js +128 -0
- package/dist/generated/engineNoticeTables.js +3 -0
- package/dist/generated/settingsSchemaTables.d.ts +8 -0
- package/dist/generated/settingsSchemaTables.js +40 -0
- package/dist/hitl/allowRuleShadow.d.ts +21 -0
- package/dist/hitl/allowRuleShadow.js +167 -0
- package/dist/hitl/askClassPair.d.ts +14 -0
- package/dist/hitl/askClassPair.js +42 -0
- package/dist/hitl/askGateWire.d.ts +1 -1
- package/dist/hitl/askGateWire.js +2 -1
- package/dist/hitl/askSurvivesPosture.d.ts +5 -0
- package/dist/hitl/askSurvivesPosture.js +17 -0
- package/dist/hitl/automaticAnswerVerdict.d.ts +21 -0
- package/dist/hitl/automaticAnswerVerdict.js +143 -0
- package/dist/hitl/crashConverged.d.ts +8 -0
- package/dist/hitl/crashConverged.js +58 -1
- package/dist/hitl/crashConvergedNotice.d.ts +4 -0
- package/dist/hitl/crashConvergedNotice.js +57 -0
- package/dist/hitl/frameRouter.d.ts +2 -0
- package/dist/hitl/frameRouter.js +66 -14
- package/dist/hitl/gateLedger.d.ts +6 -0
- package/dist/hitl/gateLedger.js +34 -5
- package/dist/hitl/hitlBridge.d.ts +7 -4
- package/dist/hitl/hitlHostSurface.d.ts +2 -0
- package/dist/hitl/hitlHostSurface.js +7 -0
- package/dist/hitl/livePendingAsk.js +24 -5
- package/dist/hitl/parkResolver.d.ts +7 -2
- package/dist/hitl/parkResolver.js +21 -7
- package/dist/hitl/persistedRulesWire.d.ts +4 -1
- package/dist/hitl/persistedRulesWire.js +9 -2
- package/dist/hitl/planReviewWire.d.ts +1 -1
- package/dist/hitl/planReviewWire.js +19 -5
- package/dist/hitl/replayedApproval.d.ts +21 -0
- package/dist/hitl/replayedApproval.js +89 -0
- package/dist/hitl/sessionPolicyDeliverable.js +20 -2
- package/dist/hitl/sessionPolicyWire.d.ts +13 -0
- package/dist/hitl/sessionPolicyWire.js +75 -2
- package/dist/hitl/suspendedReopen.js +2 -2
- package/dist/hitl/toolApprovalWire.d.ts +9 -1
- package/dist/hitl/toolApprovalWire.js +40 -40
- package/dist/hookMatcherVerdict.d.ts +29 -0
- package/dist/hookMatcherVerdict.js +266 -0
- package/dist/humanTurn.d.ts +91 -0
- package/dist/humanTurn.js +252 -0
- package/dist/humanTurnRead.d.ts +105 -0
- package/dist/humanTurnRead.js +331 -0
- package/dist/index.d.ts +38 -11
- package/dist/index.js +27 -8
- package/dist/inheritEnvWire.js +4 -5
- package/dist/liveModelCatalog.d.ts +2 -0
- package/dist/liveModelCatalog.js +51 -3
- package/dist/mcpLiveness.js +2 -1
- package/dist/memoryVerbsWire.d.ts +1 -1
- package/dist/memoryVerbsWire.js +3 -0
- package/dist/model/catalog.js +2 -1
- package/dist/model/providerPresets.d.ts +3 -1
- package/dist/model/tierVocabulary.d.ts +2 -1
- package/dist/model/tierVocabulary.js +3 -8
- package/dist/peerFrames.js +2 -2
- package/dist/permissionRuleIssue.d.ts +1 -1
- package/dist/permissionRuleIssue.js +31 -9
- package/dist/permissionsAllowGrantCapability.d.ts +2 -1
- package/dist/permissionsAllowGrantCapability.js +11 -2
- package/dist/permissionsDeclaration.d.ts +29 -0
- package/dist/permissionsDeclaration.js +155 -66
- package/dist/pluginHooksWire.js +2 -11
- package/dist/promptDelivery.d.ts +11 -3
- package/dist/promptDelivery.js +164 -29
- package/dist/promptProfileWireCaps.d.ts +2 -1
- package/dist/protocolSegment.d.ts +9 -0
- package/dist/protocolSegment.js +28 -0
- package/dist/providerRejection.d.ts +1 -0
- package/dist/providerRejection.js +20 -0
- package/dist/readDenyTiers.d.ts +10 -0
- package/dist/readDenyTiers.js +29 -0
- package/dist/request/taskRequest.js +3 -17
- package/dist/resumeRefusalCopy.d.ts +11 -0
- package/dist/resumeRefusalCopy.js +61 -4
- package/dist/rewindArchiveCapability.js +4 -4
- package/dist/rewindWireCaps.d.ts +2 -1
- package/dist/rewindWireCaps.js +19 -2
- package/dist/ruleCompileVerdict.d.ts +2 -0
- package/dist/ruleCompileVerdict.js +13 -0
- package/dist/ruleRemovalConsequence.d.ts +2 -1
- package/dist/runCancelContext.d.ts +12 -0
- package/dist/runCancelContext.js +83 -1
- package/dist/seam.d.ts +2 -0
- package/dist/seam.js +1 -1
- package/dist/seatContract.d.ts +2 -1
- package/dist/sessionMemoryStatus.d.ts +2 -4
- package/dist/sessionSyncFileHistoryCapability.d.ts +18 -0
- package/dist/sessionSyncFileHistoryCapability.js +50 -0
- package/dist/skillToolListsCapability.d.ts +18 -0
- package/dist/skillToolListsCapability.js +50 -0
- package/dist/sqlEngineCapability.js +1 -8
- package/dist/steerPriorityCapability.d.ts +18 -0
- package/dist/steerPriorityCapability.js +80 -0
- package/dist/steerReceipt.d.ts +9 -0
- package/dist/steerReceipt.js +25 -0
- package/dist/subagent/engineSubagentSteer.js +2 -9
- package/dist/supportFloor.js +2 -2
- package/dist/taskRequestWords.d.ts +7 -1
- package/dist/taskRequestWords.js +18 -8
- package/dist/toolHistoryBadTurn.d.ts +1 -0
- package/dist/toolHistoryBadTurn.js +89 -0
- package/dist/toolHistoryMismatch.d.ts +2 -1
- package/dist/toolHistoryMismatch.js +19 -6
- package/dist/toolResult.d.ts +8 -0
- package/dist/toolResult.js +47 -3
- package/dist/types/engineState.d.ts +2 -12
- package/dist/userAttachmentEnvelope.d.ts +61 -0
- package/dist/userAttachmentEnvelope.js +204 -0
- package/dist/userInvokedSkillsCapability.d.ts +18 -0
- package/dist/userInvokedSkillsCapability.js +50 -0
- package/dist/wireFailureShape.d.ts +3 -0
- package/dist/wireFailureShape.js +8 -0
- package/dist/wireRefusalCopy.d.ts +6 -0
- package/dist/wireRefusalCopy.js +26 -3
- package/dist/workflowsJournalCapability.d.ts +18 -0
- package/dist/workflowsJournalCapability.js +50 -0
- package/dist/writeProtectionCapability.d.ts +2 -4
- package/docs/INTEGRATION-CLIENTS.md +1489 -16
- package/package.json +3 -3
package/dist/liveModelCatalog.js
CHANGED
|
@@ -26,10 +26,58 @@ export function getLiveModelCatalog() {
|
|
|
26
26
|
export function normalizeLiveModelRef(ref) {
|
|
27
27
|
if (!catalog || !ref)
|
|
28
28
|
return ref;
|
|
29
|
-
|
|
29
|
+
const row = liveModelRowOf(catalog, ref);
|
|
30
|
+
if (row === undefined)
|
|
30
31
|
return ref;
|
|
31
|
-
const
|
|
32
|
-
return
|
|
32
|
+
const name = ownDataOf(row, 'name');
|
|
33
|
+
return typeof name === 'string' && name ? name : ref;
|
|
34
|
+
}
|
|
35
|
+
function ownDataOf(o, key) {
|
|
36
|
+
try {
|
|
37
|
+
const d = Object.getOwnPropertyDescriptor(o, key);
|
|
38
|
+
return d !== undefined && 'value' in d ? d.value : undefined;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function liveModelRowOf(cat, ref) {
|
|
45
|
+
const models = ownDataOf(cat, 'models');
|
|
46
|
+
if (!Array.isArray(models))
|
|
47
|
+
return undefined;
|
|
48
|
+
const n = ownDataOf(models, 'length');
|
|
49
|
+
if (typeof n !== 'number' || !Number.isSafeInteger(n) || n < 0)
|
|
50
|
+
return undefined;
|
|
51
|
+
const rows = [];
|
|
52
|
+
for (let i = 0; i < n; i += 1) {
|
|
53
|
+
const row = ownDataOf(models, String(i));
|
|
54
|
+
if (row !== null && typeof row === 'object')
|
|
55
|
+
rows.push(row);
|
|
56
|
+
}
|
|
57
|
+
return rows.find((row) => ownDataOf(row, 'name') === ref) ?? rows.find((row) => ownDataOf(row, 'id') === ref);
|
|
58
|
+
}
|
|
59
|
+
export function imageVisionOf(model, catalog = getLiveModelCatalog()) {
|
|
60
|
+
try {
|
|
61
|
+
if (model !== undefined && typeof model !== 'string')
|
|
62
|
+
return 'unknown';
|
|
63
|
+
if (catalog === null || typeof catalog !== 'object' || Array.isArray(catalog))
|
|
64
|
+
return 'unknown';
|
|
65
|
+
let target = model !== undefined && model.length > 0 ? model : undefined;
|
|
66
|
+
if (target === undefined) {
|
|
67
|
+
const def = ownDataOf(catalog, 'default');
|
|
68
|
+
target = typeof def === 'string' && def.length > 0 ? def : undefined;
|
|
69
|
+
}
|
|
70
|
+
if (target === undefined)
|
|
71
|
+
return 'unknown';
|
|
72
|
+
const row = liveModelRowOf(catalog, target);
|
|
73
|
+
if (row === undefined)
|
|
74
|
+
return 'unknown';
|
|
75
|
+
const vision = ownDataOf(row, 'vision');
|
|
76
|
+
return vision === true ? 'yes' : vision === false ? 'no' : 'unknown';
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return 'unknown';
|
|
80
|
+
}
|
|
33
81
|
}
|
|
34
82
|
export function liveDefaultModelName() {
|
|
35
83
|
if (!catalog?.default)
|
package/dist/mcpLiveness.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { CORE_MCP_LIVENESS_STATES } from './generated/engineFactTables.js';
|
|
2
|
+
export const MCP_LIVENESS_STATES = CORE_MCP_LIVENESS_STATES;
|
|
2
3
|
void MCP_LIVENESS_STATES;
|
|
3
4
|
void true;
|
|
4
5
|
void true;
|
|
@@ -19,7 +19,7 @@ export interface MemoryFacade {
|
|
|
19
19
|
signal?: AbortSignal;
|
|
20
20
|
}): Promise<MemoryOriginClearReceipt>;
|
|
21
21
|
}
|
|
22
|
-
export declare const MEMORY_VERB_REFUSAL_CAUSES: readonly ["face_absent", "client_too_old", "unreadable_request", "store_absent", "operator_only", "unauthorized", "service_token_required", "id_invalid", "request_id_required", "body_shape", "query_invalid", "selector_invalid", "evidence_unavailable", "selector_mismatch", "census_incomplete", "clear_unattributed", "clear_invalid", "clear_not_marked", "clear_challenged", "clear_conflict", "clear_pending"];
|
|
22
|
+
export declare const MEMORY_VERB_REFUSAL_CAUSES: readonly ["face_absent", "client_too_old", "unreadable_request", "store_absent", "operator_only", "operators_unconfigured", "unauthorized", "service_token_required", "id_invalid", "request_id_required", "body_shape", "query_invalid", "selector_invalid", "evidence_unavailable", "selector_mismatch", "census_incomplete", "clear_unattributed", "clear_invalid", "clear_not_marked", "clear_challenged", "clear_conflict", "clear_pending"];
|
|
23
23
|
export type MemoryVerbRefusalCause = (typeof MEMORY_VERB_REFUSAL_CAUSES)[number];
|
|
24
24
|
export declare const MEMORY_VERB_UNKNOWN_WHYS: readonly ["no_verdict", "server_fault", "control_plane_corrupt", "clear_unknown", "clear_failed", "result_unreadable", "unsupported_version", "identity_mismatch", "unclassified"];
|
|
25
25
|
export type MemoryVerbUnknownWhy = (typeof MEMORY_VERB_UNKNOWN_WHYS)[number];
|
package/dist/memoryVerbsWire.js
CHANGED
|
@@ -8,6 +8,7 @@ export const MEMORY_VERB_REFUSAL_CAUSES = Object.freeze([
|
|
|
8
8
|
'unreadable_request',
|
|
9
9
|
'store_absent',
|
|
10
10
|
'operator_only',
|
|
11
|
+
'operators_unconfigured',
|
|
11
12
|
'unauthorized',
|
|
12
13
|
'service_token_required',
|
|
13
14
|
'id_invalid',
|
|
@@ -51,6 +52,8 @@ export function classifyMemoryFailure(e) {
|
|
|
51
52
|
return refusedBy('unauthorized', message);
|
|
52
53
|
case 'auth.operator_only':
|
|
53
54
|
return refusedBy('operator_only', message);
|
|
55
|
+
case 'capability.operator_principals_required':
|
|
56
|
+
return refusedBy('operators_unconfigured', message);
|
|
54
57
|
case 'auth.service_token_required':
|
|
55
58
|
return refusedBy('service_token_required', message);
|
|
56
59
|
case 'capability.memory_engine_required':
|
package/dist/model/catalog.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PROVIDER_PRESETS } from './providerPresets.js';
|
|
2
|
+
import { SETTINGS_MODEL_API_WORDS } from '../generated/settingsSchemaTables.js';
|
|
2
3
|
export const CATALOG_SCHEMA_VERSION_MIN = 1;
|
|
3
4
|
export const CATALOG_SCHEMA_VERSION_MAX = 1;
|
|
4
5
|
export function isSupportedCatalogSchemaVersion(v) {
|
|
@@ -15,7 +16,7 @@ function isProviderRow(v) {
|
|
|
15
16
|
r.id.length > 0 &&
|
|
16
17
|
typeof r.name === 'string' &&
|
|
17
18
|
typeof r.baseUrl === 'string' &&
|
|
18
|
-
|
|
19
|
+
typeof r.api === 'string' && SETTINGS_MODEL_API_WORDS.includes(r.api) &&
|
|
19
20
|
typeof r.authEnv === 'string' &&
|
|
20
21
|
Array.isArray(r.models));
|
|
21
22
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { SETTINGS_MODEL_API_WORDS } from '../generated/settingsSchemaTables.js';
|
|
2
|
+
export type ModelApiWord = (typeof SETTINGS_MODEL_API_WORDS)[number];
|
|
1
3
|
export type PresetModel = {
|
|
2
4
|
id: string;
|
|
3
5
|
contextWindow: number;
|
|
@@ -8,7 +10,7 @@ export type ProviderPreset = {
|
|
|
8
10
|
id: string;
|
|
9
11
|
name: string;
|
|
10
12
|
baseUrl: string;
|
|
11
|
-
api:
|
|
13
|
+
api: ModelApiWord;
|
|
12
14
|
authEnv: string;
|
|
13
15
|
models: PresetModel[];
|
|
14
16
|
modelViaFamily?: boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { CORE_DEFAULT_TIER_ORDER } from '../generated/engineFactTables.js';
|
|
2
|
+
export type Tier = (typeof CORE_DEFAULT_TIER_ORDER)[number];
|
|
2
3
|
export declare const TIER_ORDER: readonly Tier[];
|
|
3
4
|
export declare const SURFACED_TIERS: readonly Tier[];
|
|
4
5
|
export declare const CC_TIER_ALIASES: Readonly<Record<string, Tier>>;
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { CORE_CC_MODEL_TIER_ALIASES, CORE_DEFAULT_TIER_ORDER } from '../generated/engineFactTables.js';
|
|
2
|
+
export const TIER_ORDER = CORE_DEFAULT_TIER_ORDER;
|
|
2
3
|
export const SURFACED_TIERS = ['max', 'pro', 'flash', 'lite'];
|
|
3
|
-
export const CC_TIER_ALIASES =
|
|
4
|
-
fable: 'max',
|
|
5
|
-
mythos: 'max',
|
|
6
|
-
opus: 'pro',
|
|
7
|
-
sonnet: 'flash',
|
|
8
|
-
haiku: 'lite',
|
|
9
|
-
};
|
|
4
|
+
export const CC_TIER_ALIASES = CORE_CC_MODEL_TIER_ALIASES;
|
|
10
5
|
export const DEFAULT_TIER = 'pro';
|
|
11
6
|
export const TIER_BLURBS = {
|
|
12
7
|
ultra: 'reserved above max — binds when a stronger model lands',
|
package/dist/peerFrames.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { applyDisplayFace, LEGACY_NAME_FACE } from './displayUntrusted.js';
|
|
2
|
-
import { CORE_ENGINE_AUTHORITY_ENVELOPE_TAGS } from './generated/engineFactTables.js';
|
|
2
|
+
import { CORE_ENGINE_AUTHORITY_ENVELOPE_TAGS, CORE_PERMISSION_MODE_CLASSES } from './generated/engineFactTables.js';
|
|
3
3
|
const WIRE_KEY_FROM = 'from';
|
|
4
4
|
const WIRE_KEY_BODY = 'body';
|
|
5
5
|
const WIRE_KEY_KIND = 'kind';
|
|
@@ -21,7 +21,7 @@ export const AGENT_MESSAGE_TAG = 'agent-message';
|
|
|
21
21
|
export const CROSS_SESSION_MESSAGE_TAG = 'cross-session-message';
|
|
22
22
|
export const PEER_FRAME_LANES = Object.freeze(['agent_message', 'cross_session_message', 'cross_session_notice']);
|
|
23
23
|
export const CROSS_SESSION_NOTICE_KINDS = Object.freeze(['delivery_notice', 'idle_notice']);
|
|
24
|
-
export const PEER_MODE_CLASSES =
|
|
24
|
+
export const PEER_MODE_CLASSES = CORE_PERMISSION_MODE_CLASSES;
|
|
25
25
|
function dataProp(o, key) {
|
|
26
26
|
if (o === null || typeof o !== 'object')
|
|
27
27
|
return undefined;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare const PERMISSION_RULE_ISSUE_CODES: readonly string[];
|
|
2
2
|
export declare const RETIRED_PERMISSION_RULE_ISSUE_CODES: readonly string[];
|
|
3
|
-
export declare function permissionRuleIssueDetail(code: unknown, message: unknown): string;
|
|
3
|
+
export declare function permissionRuleIssueDetail(code: unknown, message: unknown, rule?: string): string;
|
|
@@ -3,15 +3,15 @@ export const PERMISSION_RULE_ISSUE_CODES = Object.freeze([
|
|
|
3
3
|
'invalid.empty_tool',
|
|
4
4
|
'invalid.paren',
|
|
5
5
|
'invalid.param_split',
|
|
6
|
-
'invalid.allow_param_rule',
|
|
7
6
|
'invalid.primary_field',
|
|
8
7
|
'invalid.cap_exceeded',
|
|
9
|
-
'unsupported.
|
|
8
|
+
'unsupported.allow',
|
|
9
|
+
'invalid.behavior',
|
|
10
10
|
'invalid.command_rule',
|
|
11
|
+
'invalid.entry_type',
|
|
11
12
|
'unsupported.param_unknown',
|
|
12
13
|
'unsupported.param_non_scalar',
|
|
13
14
|
'unsupported.tool_unknown',
|
|
14
|
-
'unsupported.file_glob',
|
|
15
15
|
'unsupported.path_base',
|
|
16
16
|
'unsupported.mcp_paren',
|
|
17
17
|
'unsupported.covering_paren',
|
|
@@ -21,22 +21,44 @@ const ISSUE_MESSAGE_MAX = 200;
|
|
|
21
21
|
const ISSUE_SENTENCES = Object.freeze({
|
|
22
22
|
'invalid.empty_tool': 'this rule is invalid: it names no tool',
|
|
23
23
|
'invalid.paren': 'this rule is invalid: its parentheses do not parse (escape a literal one as \\( or \\))',
|
|
24
|
-
'invalid.param_split': 'this rule is invalid:
|
|
25
|
-
'invalid.allow_param_rule': 'this rule is invalid: an allow rule cannot carry a parameter pattern — only bare tool rules auto-allow',
|
|
24
|
+
'invalid.param_split': 'this rule is invalid: its parentheses do not hold a parameter rule written name:pattern',
|
|
26
25
|
'invalid.primary_field': "this rule is invalid: it patterns the tool's primary field, which matches the whole trimmed string rather than a prefix",
|
|
27
26
|
'invalid.cap_exceeded': 'this rule set is invalid: it is over one of the deployment caps (rule count, rule length, pattern length, or star count)',
|
|
27
|
+
'invalid.behavior': 'this rule is invalid: its behavior is neither deny nor ask, so it would never fire',
|
|
28
28
|
'invalid.command_rule': 'this rule is invalid: the command pattern was rejected by the command-rule validator',
|
|
29
|
-
'
|
|
29
|
+
'invalid.entry_type': 'this allow list is invalid: it must be a list of rule strings, and it or one of its entries is not a string',
|
|
30
|
+
'unsupported.allow': 'an allow rule is not supported in a rule set that only says deny or ask — a standing approval belongs on the allow list instead',
|
|
30
31
|
'unsupported.param_unknown': 'this parameter rule is not supported: the tool carries no such parameter, so it could never match',
|
|
31
32
|
'unsupported.param_non_scalar': 'this parameter rule is not supported: that parameter holds an object or an array, so it could never match',
|
|
32
33
|
'unsupported.tool_unknown': "this rule is not supported on this leg: the resolver it supplied does not know the tool, so the rule's face cannot be checked",
|
|
33
|
-
'unsupported.file_glob': 'a standing approval by path belongs in the consent store, so this allow rule is not supported here (deny and ask path rules do compile)',
|
|
34
34
|
'unsupported.path_base': 'this path rule is not supported as spelled: it needs a base this policy was not given, so it would reach nothing and is refused rather than compiled',
|
|
35
35
|
'unsupported.mcp_paren': 'a parenthesised parameter rule is not supported on an MCP tool name',
|
|
36
36
|
'unsupported.covering_paren': 'a parenthesised parameter rule is not supported on a covering protocol name — the parameter grammar is keyed by an exact tool name, so no mounted tool could ever bear it',
|
|
37
|
+
'invalid.allow_param_rule': 'this rule is invalid: an allow rule cannot carry a parameter pattern — only bare tool rules auto-allow',
|
|
38
|
+
'unsupported.bash_prefix': 'a standing approval for a command belongs in the persisted-rule store, so this allow rule is not supported here (deny and ask rules with the same shape do compile)',
|
|
39
|
+
'unsupported.file_glob': 'a standing approval by path belongs in the consent store, so this allow rule is not supported here (deny and ask path rules do compile)',
|
|
37
40
|
});
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
const PARAM_SPLIT_WITH_COLON = 'this rule is invalid: a parameter rule is written name:pattern, and the name before the colon or the pattern after it is empty';
|
|
42
|
+
const PARAM_SPLIT_NO_COLON = 'this rule is invalid: there is no colon inside the parentheses, so this is not a parameter rule (a parameter rule is written name:pattern)';
|
|
43
|
+
function colonInsideParens(rule) {
|
|
44
|
+
if (typeof rule !== 'string')
|
|
45
|
+
return undefined;
|
|
46
|
+
for (let i = 0; i < rule.length; i += 1) {
|
|
47
|
+
const ch = rule[i];
|
|
48
|
+
if (ch === '\\') {
|
|
49
|
+
i += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (ch === '(')
|
|
53
|
+
return rule.indexOf(':', i + 1) !== -1;
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
export function permissionRuleIssueDetail(code, message, rule) {
|
|
58
|
+
const colon = code === 'invalid.param_split' ? colonInsideParens(rule) : undefined;
|
|
59
|
+
const known = colon !== undefined
|
|
60
|
+
? colon ? PARAM_SPLIT_WITH_COLON : PARAM_SPLIT_NO_COLON
|
|
61
|
+
: typeof code === 'string' && Object.hasOwn(ISSUE_SENTENCES, code) ? ISSUE_SENTENCES[code] : undefined;
|
|
40
62
|
const text = typeof message === 'string' && message.length > 0
|
|
41
63
|
? capForDisplay(message, ISSUE_MESSAGE_MAX)
|
|
42
64
|
: '';
|
|
@@ -12,6 +12,7 @@ export declare function noteEngineCapsForPermissionsAllowGrant(baseUrl: string,
|
|
|
12
12
|
}): void;
|
|
13
13
|
export declare function observedPermissionsAllowGrant(baseUrl?: string | undefined): PermissionsAllowGrantReading;
|
|
14
14
|
export declare function permissionsAllowGrantAvailable(reading: PermissionsAllowGrantReading): boolean;
|
|
15
|
-
export declare function
|
|
15
|
+
export declare function allowRulesGate(reading: PermissionsAllowGrantReading, settingsRead: 'clean' | 'partial' | 'unreadable' | undefined): 'open' | 'capability_off' | 'settings_read_not_clean';
|
|
16
|
+
export declare function permissionsAllowGrantDoctorDetail(reading: PermissionsAllowGrantReading, settingsRead?: 'clean' | 'partial' | 'unreadable'): string;
|
|
16
17
|
export declare function forgetPermissionsAllowGrantReading(baseUrl: string | undefined): void;
|
|
17
18
|
export declare function __resetPermissionsAllowGrantReadingsForTests(): void;
|
|
@@ -44,6 +44,11 @@ export function permissionsAllowGrantAvailable(reading) {
|
|
|
44
44
|
return false;
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
export function allowRulesGate(reading, settingsRead) {
|
|
48
|
+
if (!permissionsAllowGrantAvailable(reading))
|
|
49
|
+
return 'capability_off';
|
|
50
|
+
return settingsRead === 'clean' ? 'open' : 'settings_read_not_clean';
|
|
51
|
+
}
|
|
47
52
|
function ownReadingField(reading, key) {
|
|
48
53
|
try {
|
|
49
54
|
if (reading === null || typeof reading !== 'object' || Array.isArray(reading))
|
|
@@ -54,10 +59,14 @@ function ownReadingField(reading, key) {
|
|
|
54
59
|
return undefined;
|
|
55
60
|
}
|
|
56
61
|
}
|
|
57
|
-
export function permissionsAllowGrantDoctorDetail(reading) {
|
|
58
|
-
|
|
62
|
+
export function permissionsAllowGrantDoctorDetail(reading, settingsRead) {
|
|
63
|
+
const gate = allowRulesGate(reading, settingsRead);
|
|
64
|
+
if (gate === 'open') {
|
|
59
65
|
return 'allow rules sent to the engine — it reads them as rules, not as an exclusive list: a matching call counts as answered for, and the engine still raises its own prompts where it requires them';
|
|
60
66
|
}
|
|
67
|
+
if (gate === 'settings_read_not_clean') {
|
|
68
|
+
return 'allow rules from settings files kept on this side — this engine reads allow rules as rules, but the settings read that produced them was not reported clean (a settings file was unreadable or had a problem, or no read health was given), so they are not sent; command-line and session allow rules are still sent, and matching approvals are still answered here';
|
|
69
|
+
}
|
|
61
70
|
const kind = ownReadingField(reading, 'kind');
|
|
62
71
|
if (kind === 'present' && ownReadingField(reading, 'grants') === false) {
|
|
63
72
|
return 'allow rules kept on this side — this engine says it does not read allow rules as rules of that kind, so they are not sent and matching approvals are still answered here';
|
|
@@ -12,6 +12,7 @@ export interface PermissionsDeclarationInput {
|
|
|
12
12
|
readonly allow: readonly string[];
|
|
13
13
|
readonly origins?: WireRuleOrigins;
|
|
14
14
|
readonly cliDeny?: readonly string[];
|
|
15
|
+
readonly settingsRead: 'clean' | 'partial' | 'unreadable';
|
|
15
16
|
}
|
|
16
17
|
export interface PermissionsDeclarationBuckets {
|
|
17
18
|
deny?: string[];
|
|
@@ -21,5 +22,33 @@ export interface PermissionsDeclarationBuckets {
|
|
|
21
22
|
export interface PermissionsDeclaration {
|
|
22
23
|
permissions?: PermissionsDeclarationBuckets;
|
|
23
24
|
}
|
|
25
|
+
export declare const PERMISSIONS_KEPT_REASONS: readonly ["allow_capability_off", "settings_read_not_clean", "empty_rule", "paren_in_tool_name", "retired_tool_name", "unprefixed_namespaced_name", "incomplete_protocol_name", "unminted_protocol_segment", "home_relative_path", "compile_refused", "content_form_not_grantable", "judge_failed", "duplicate"];
|
|
26
|
+
export type PermissionsKeptReason = (typeof PERMISSIONS_KEPT_REASONS)[number];
|
|
27
|
+
export interface PermissionsKeptRule {
|
|
28
|
+
rule: string;
|
|
29
|
+
bucket: 'deny' | 'ask' | 'allow';
|
|
30
|
+
reason: PermissionsKeptReason;
|
|
31
|
+
}
|
|
32
|
+
export interface PermissionsRewrittenRule {
|
|
33
|
+
from: string;
|
|
34
|
+
to: string;
|
|
35
|
+
bucket: 'deny' | 'ask' | 'allow';
|
|
36
|
+
}
|
|
37
|
+
export interface PermissionsUncheckedRule {
|
|
38
|
+
rule: string;
|
|
39
|
+
bucket: 'deny' | 'ask';
|
|
40
|
+
}
|
|
41
|
+
export interface PermissionsUnreachableRule {
|
|
42
|
+
rule: string;
|
|
43
|
+
bucket: 'deny' | 'ask';
|
|
44
|
+
mintedPrefix?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface PermissionsDeclarationReport extends PermissionsDeclaration {
|
|
47
|
+
kept: PermissionsKeptRule[];
|
|
48
|
+
rewritten: PermissionsRewrittenRule[];
|
|
49
|
+
unchecked: PermissionsUncheckedRule[];
|
|
50
|
+
unreachable: PermissionsUnreachableRule[];
|
|
51
|
+
}
|
|
24
52
|
export declare function permissionsDeclaration(input: PermissionsDeclarationInput, caps: PermissionsAllowGrantReading): PermissionsDeclaration;
|
|
53
|
+
export declare function permissionsDeclarationReport(input: PermissionsDeclarationInput, caps: PermissionsAllowGrantReading): PermissionsDeclarationReport;
|
|
25
54
|
export {};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { hasCoreValuePort, protocolOf, retiredToolNames, ruleToolGrammarOf
|
|
2
|
-
import {
|
|
1
|
+
import { hasCoreValuePort, protocolOf, retiredToolNames, ruleToolGrammarOf } from './coreValuePorts.js';
|
|
2
|
+
import { protocolSegmentOf } from './protocolSegment.js';
|
|
3
|
+
import { ruleCompileVerdict } from './ruleCompileVerdict.js';
|
|
4
|
+
import { allowRulesGate } from './permissionsAllowGrantCapability.js';
|
|
3
5
|
const RULE_TRUST_ORDER = [
|
|
4
6
|
'policySettings',
|
|
5
7
|
'cliArg',
|
|
@@ -9,6 +11,21 @@ const RULE_TRUST_ORDER = [
|
|
|
9
11
|
'localSettings',
|
|
10
12
|
'projectSettings',
|
|
11
13
|
];
|
|
14
|
+
export const PERMISSIONS_KEPT_REASONS = Object.freeze([
|
|
15
|
+
'allow_capability_off',
|
|
16
|
+
'settings_read_not_clean',
|
|
17
|
+
'empty_rule',
|
|
18
|
+
'paren_in_tool_name',
|
|
19
|
+
'retired_tool_name',
|
|
20
|
+
'unprefixed_namespaced_name',
|
|
21
|
+
'incomplete_protocol_name',
|
|
22
|
+
'unminted_protocol_segment',
|
|
23
|
+
'home_relative_path',
|
|
24
|
+
'compile_refused',
|
|
25
|
+
'content_form_not_grantable',
|
|
26
|
+
'judge_failed',
|
|
27
|
+
'duplicate',
|
|
28
|
+
]);
|
|
12
29
|
function normalizeLegacyToolName(name) {
|
|
13
30
|
switch (name) {
|
|
14
31
|
case 'Task':
|
|
@@ -61,15 +78,15 @@ function requireRulePorts() {
|
|
|
61
78
|
throw new Error(`permissionsDeclaration: 规则判据端口缺席(${missing.join(' / ')})—— 先用 installCoreValuePorts 装上 core 的同名实现。` +
|
|
62
79
|
'缺席不等于全部合格:不判就发会让整份请求被引擎拒收,不判就删会静默丢掉 deny 规则,所以这里拒绝装配。');
|
|
63
80
|
}
|
|
64
|
-
function
|
|
81
|
+
function wireIssue(name) {
|
|
65
82
|
if (name.includes('('))
|
|
66
|
-
return
|
|
83
|
+
return 'paren_in_tool_name';
|
|
67
84
|
if (retiredToolNames().has(name))
|
|
68
|
-
return
|
|
85
|
+
return 'retired_tool_name';
|
|
69
86
|
const ns = protocolOf(name);
|
|
70
87
|
if (ns === undefined)
|
|
71
|
-
return
|
|
72
|
-
return ns.parse(name) !== undefined;
|
|
88
|
+
return name.includes('__') ? 'unprefixed_namespaced_name' : undefined;
|
|
89
|
+
return ns.parse(name) !== undefined ? undefined : 'incomplete_protocol_name';
|
|
73
90
|
}
|
|
74
91
|
function wholeServerRuleName(name) {
|
|
75
92
|
const read = name.trim();
|
|
@@ -79,24 +96,19 @@ function wholeServerRuleName(name) {
|
|
|
79
96
|
const peer = read.slice(ns.prefix.length);
|
|
80
97
|
return peer !== '' && !peer.includes('__') && !peer.endsWith('_') ? `${read}__*` : name;
|
|
81
98
|
}
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
catch {
|
|
91
|
-
return 'unknown';
|
|
92
|
-
}
|
|
99
|
+
const compileVerdict = ruleCompileVerdict;
|
|
100
|
+
const kept = (reason) => ({ sent: false, reason });
|
|
101
|
+
function sentFate(wire, toolName, unchecked) {
|
|
102
|
+
const segment = protocolSegmentOf(toolName);
|
|
103
|
+
return segment.kind === 'unminted'
|
|
104
|
+
? { sent: true, wire, unchecked, unreachable: segment.minted !== undefined ? { minted: segment.minted } : {} }
|
|
105
|
+
: { sent: true, wire, unchecked };
|
|
93
106
|
}
|
|
94
|
-
function
|
|
95
|
-
const out = new Set();
|
|
107
|
+
function judgeList(rules, behavior) {
|
|
96
108
|
let portsChecked = false;
|
|
97
|
-
|
|
98
|
-
if (
|
|
99
|
-
|
|
109
|
+
return rules.map((rule) => {
|
|
110
|
+
if (rule === '')
|
|
111
|
+
return kept('empty_rule');
|
|
100
112
|
if (!portsChecked) {
|
|
101
113
|
requireRulePorts();
|
|
102
114
|
portsChecked = true;
|
|
@@ -104,50 +116,85 @@ function wireSubset(rules, behavior) {
|
|
|
104
116
|
const parsed = parseRule(rule);
|
|
105
117
|
if (parsed.ruleContent === undefined) {
|
|
106
118
|
const name = wholeServerRuleName(parsed.toolName);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
119
|
+
const issue = wireIssue(name);
|
|
120
|
+
if (issue !== undefined)
|
|
121
|
+
return kept(issue);
|
|
122
|
+
if (behavior === 'allow') {
|
|
123
|
+
const segment = protocolSegmentOf(name);
|
|
124
|
+
if (segment.kind === 'unminted')
|
|
125
|
+
return kept('unminted_protocol_segment');
|
|
126
|
+
if (segment.kind === 'unknown')
|
|
127
|
+
return kept('judge_failed');
|
|
128
|
+
}
|
|
129
|
+
const verdict = compileVerdict(name, behavior === 'ask' ? 'ask' : 'deny');
|
|
130
|
+
if (verdict === 'refused')
|
|
131
|
+
return kept('compile_refused');
|
|
132
|
+
if (verdict === 'unknown' && behavior === 'allow')
|
|
133
|
+
return kept('judge_failed');
|
|
134
|
+
return behavior === 'allow' ? { sent: true, wire: name, unchecked: false } : sentFate(name, name, verdict === 'unknown');
|
|
116
135
|
}
|
|
117
|
-
|
|
118
|
-
|
|
136
|
+
const issue = wireIssue(parsed.toolName);
|
|
137
|
+
if (issue !== undefined)
|
|
138
|
+
return kept(issue);
|
|
119
139
|
if (ruleToolGrammarOf(parsed.toolName) === 'path' && parsed.ruleContent.startsWith('~/'))
|
|
120
|
-
|
|
140
|
+
return kept('home_relative_path');
|
|
141
|
+
if (behavior === 'allow')
|
|
142
|
+
return kept('content_form_not_grantable');
|
|
121
143
|
const verdict = compileVerdict(rule, behavior);
|
|
122
|
-
if (verdict === '
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
144
|
+
if (verdict === 'refused')
|
|
145
|
+
return kept('compile_refused');
|
|
146
|
+
return sentFate(rule, parsed.toolName, verdict === 'unknown');
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function outsideSettingsFiles(origin) {
|
|
150
|
+
return origin === 'cliArg' || origin === 'session';
|
|
126
151
|
}
|
|
127
|
-
function
|
|
128
|
-
const
|
|
152
|
+
function judgeBucket(raw, behavior, originOf, cli, settingsGate) {
|
|
153
|
+
const firstSlot = new Map();
|
|
154
|
+
for (const s of raw)
|
|
155
|
+
if (!firstSlot.has(s.rule))
|
|
156
|
+
firstSlot.set(s.rule, s);
|
|
129
157
|
const groups = RULE_TRUST_ORDER.map(() => []);
|
|
130
158
|
const rankOf = (origin) => RULE_TRUST_ORDER.indexOf(origin);
|
|
131
159
|
if (originOf !== undefined) {
|
|
132
160
|
for (const [r, origin] of originOf) {
|
|
133
161
|
const rank = rankOf(origin);
|
|
134
|
-
if (rank >= 0 && typeof r === 'string' &&
|
|
162
|
+
if (rank >= 0 && typeof r === 'string' && firstSlot.has(r))
|
|
135
163
|
groups[rank].push(r);
|
|
136
164
|
}
|
|
137
165
|
}
|
|
138
|
-
const unknownOrigin = [...
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
166
|
+
const unknownOrigin = [...firstSlot.keys()].filter((r) => originOf === undefined || rankOf(originOf.get(r)) < 0);
|
|
167
|
+
const fateOfRule = new Map();
|
|
168
|
+
const sent = [];
|
|
169
|
+
const winnerOf = new Map();
|
|
170
|
+
const cliFates = cli === undefined ? [] : [...cli.fates];
|
|
171
|
+
const place = (slot, fate) => {
|
|
172
|
+
if (!fate.sent)
|
|
173
|
+
return fate;
|
|
174
|
+
if (winnerOf.has(fate.wire))
|
|
175
|
+
return kept('duplicate');
|
|
176
|
+
winnerOf.set(fate.wire, slot);
|
|
177
|
+
sent.push(fate.wire);
|
|
178
|
+
return fate;
|
|
179
|
+
};
|
|
180
|
+
const appendGroup = (group, origin) => {
|
|
181
|
+
const held = settingsGate !== undefined && !outsideSettingsFiles(origin);
|
|
182
|
+
const fates = held ? group.map(() => kept(settingsGate)) : judgeList(group, behavior);
|
|
183
|
+
group.forEach((r, k) => fateOfRule.set(r, place(firstSlot.get(r), fates[k])));
|
|
143
184
|
};
|
|
144
185
|
RULE_TRUST_ORDER.forEach((origin, rank) => {
|
|
145
|
-
if (origin === 'cliArg')
|
|
146
|
-
|
|
147
|
-
|
|
186
|
+
if (origin === 'cliArg' && cli !== undefined)
|
|
187
|
+
cli.slots.forEach((s, k) => (cliFates[k] = place(s, cliFates[k])));
|
|
188
|
+
appendGroup(groups[rank], origin);
|
|
189
|
+
});
|
|
190
|
+
appendGroup(unknownOrigin, undefined);
|
|
191
|
+
const fates = raw.map((s) => {
|
|
192
|
+
const f = fateOfRule.get(s.rule);
|
|
193
|
+
if (firstSlot.get(s.rule) === s)
|
|
194
|
+
return f;
|
|
195
|
+
return f.sent || f.reason === 'duplicate' ? kept('duplicate') : f;
|
|
148
196
|
});
|
|
149
|
-
|
|
150
|
-
return [...out];
|
|
197
|
+
return { sent, fates: [...fates, ...cliFates], winnerOf };
|
|
151
198
|
}
|
|
152
199
|
const WHO = 'permissionsDeclaration';
|
|
153
200
|
function ownField(obj, key, where) {
|
|
@@ -192,7 +239,8 @@ function originMap(v, key) {
|
|
|
192
239
|
}
|
|
193
240
|
return snap;
|
|
194
241
|
}
|
|
195
|
-
|
|
242
|
+
const slotsOf = (list, name) => (list ?? []).map((rule, at) => ({ rule, list: name, at }));
|
|
243
|
+
function assemble(input, caps) {
|
|
196
244
|
if (input === null || typeof input !== 'object' || Array.isArray(input)) {
|
|
197
245
|
throw new TypeError(`${WHO}: 入参必须是对象 —— 收到 ${input === null ? 'null' : Array.isArray(input) ? 'array' : `typeof=${typeof input}`}。`);
|
|
198
246
|
}
|
|
@@ -211,17 +259,58 @@ export function permissionsDeclaration(input, caps) {
|
|
|
211
259
|
const ol = originMap(ownField(originsRaw, 'allow', 'origins.'), 'allow');
|
|
212
260
|
origins = { ...(od ? { deny: od } : {}), ...(oa ? { ask: oa } : {}), ...(ol ? { allow: ol } : {}) };
|
|
213
261
|
}
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
262
|
+
const gate = allowRulesGate(caps, ownField(input, 'settingsRead', ''));
|
|
263
|
+
const cliSlots = slotsOf(cliDeny, 'cliDeny');
|
|
264
|
+
const cli = cliDeny === undefined ? undefined : { slots: cliSlots, fates: judgeList(cliDeny, 'deny') };
|
|
265
|
+
const denySlots = slotsOf(deny, 'deny');
|
|
266
|
+
const askSlots = slotsOf(ask, 'ask');
|
|
267
|
+
const allowSlots = slotsOf(allow, 'allow');
|
|
268
|
+
const denyJ = judgeBucket(denySlots, 'deny', origins.deny, cli);
|
|
269
|
+
const askJ = judgeBucket(askSlots, 'ask', origins.ask, undefined);
|
|
270
|
+
const allowJ = gate === 'capability_off'
|
|
271
|
+
? { sent: [], fates: allowSlots.map(() => kept('allow_capability_off')), winnerOf: new Map() }
|
|
272
|
+
: judgeBucket(allowSlots, 'allow', origins.allow, undefined, gate === 'settings_read_not_clean' ? 'settings_read_not_clean' : undefined);
|
|
273
|
+
const buckets = {};
|
|
274
|
+
if (denyJ.sent.length > 0)
|
|
275
|
+
buckets.deny = [...denyJ.sent];
|
|
276
|
+
if (askJ.sent.length > 0)
|
|
277
|
+
buckets.ask = [...askJ.sent];
|
|
278
|
+
if (allowJ.sent.length > 0)
|
|
279
|
+
buckets.allow = [...allowJ.sent];
|
|
280
|
+
const keptRows = [];
|
|
281
|
+
const rewritten = [];
|
|
282
|
+
const unchecked = [];
|
|
283
|
+
const unreachable = [];
|
|
284
|
+
const rows = [
|
|
285
|
+
['deny', [...denySlots, ...cliSlots], denyJ],
|
|
286
|
+
['ask', askSlots, askJ],
|
|
287
|
+
['allow', allowSlots, allowJ],
|
|
288
|
+
];
|
|
289
|
+
for (const [bucket, slots, j] of rows) {
|
|
290
|
+
slots.forEach((s, k) => {
|
|
291
|
+
const f = j.fates[k];
|
|
292
|
+
if (!f.sent)
|
|
293
|
+
keptRows.push({ rule: s.rule, bucket, reason: f.reason });
|
|
294
|
+
});
|
|
295
|
+
for (const wire of j.sent) {
|
|
296
|
+
const winner = j.winnerOf.get(wire);
|
|
297
|
+
if (winner.rule !== wire)
|
|
298
|
+
rewritten.push({ from: winner.rule, to: wire, bucket });
|
|
299
|
+
const f = (winner.list === 'cliDeny' ? j.fates[denySlots.length + winner.at] : j.fates[winner.at]);
|
|
300
|
+
if (f.sent && f.unchecked && bucket !== 'allow')
|
|
301
|
+
unchecked.push({ rule: wire, bucket });
|
|
302
|
+
if (f.sent && f.unreachable !== undefined && bucket !== 'allow') {
|
|
303
|
+
unreachable.push({ rule: wire, bucket, ...(f.unreachable.minted !== undefined ? { mintedPrefix: f.unreachable.minted } : {}) });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return { buckets, report: { kept: keptRows, rewritten, unchecked, unreachable } };
|
|
308
|
+
}
|
|
309
|
+
export function permissionsDeclaration(input, caps) {
|
|
310
|
+
const { buckets } = assemble(input, caps);
|
|
311
|
+
return Object.keys(buckets).length > 0 ? { permissions: buckets } : {};
|
|
312
|
+
}
|
|
313
|
+
export function permissionsDeclarationReport(input, caps) {
|
|
314
|
+
const { buckets, report } = assemble(input, caps);
|
|
315
|
+
return { ...(Object.keys(buckets).length > 0 ? { permissions: buckets } : {}), ...report };
|
|
227
316
|
}
|
package/dist/pluginHooksWire.js
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
import { displayUntrusted } from './displayUntrusted.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
'PostToolUse',
|
|
5
|
-
'PostToolUseFailure',
|
|
6
|
-
'PostToolBatch',
|
|
7
|
-
'PreCompact',
|
|
8
|
-
'PostCompact',
|
|
9
|
-
'Stop',
|
|
10
|
-
'StopFailure',
|
|
11
|
-
'UserPromptSubmit',
|
|
12
|
-
];
|
|
2
|
+
import { SETTINGS_ENGINE_OWNED_HOOK_EVENTS } from './generated/settingsSchemaTables.js';
|
|
3
|
+
export const ENGINE_FIRED_HOOK_EVENTS = SETTINGS_ENGINE_OWNED_HOOK_EVENTS;
|
|
13
4
|
export const PLUGIN_HOOK_DISPOSITIONS = ['engine', 'shell', 'not_run'];
|
|
14
5
|
export const PLUGIN_HOOK_REASONS = [
|
|
15
6
|
'projected',
|