@corca-org/ceal-host-linux-arm64 1.0.8 → 1.0.10
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/README.md +2 -2
- package/bin/ceal-host +0 -0
- package/libexec/ceal-host/claude-hook.mjs +149 -46
- package/libexec/ceal-host/claude-invocation-authentication.mjs +103 -127
- package/libexec/ceal-host/claude-producer.mjs +76 -24
- package/libexec/ceal-host/codex-hook.mjs +148 -47
- package/libexec/ceal-host/codex-invocation-authentication.mjs +136 -131
- package/libexec/ceal-host/codex-producer.mjs +136 -32
- package/libexec/ceal-host/control.mjs +157 -40
- package/libexec/ceal-host/relay.mjs +240 -58
- package/package.json +1 -1
- package/share/ceal-host/bundle-manifest.json +12 -12
- package/share/ceal-host/bundle-manifest.sigstore.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# @corca-org/ceal-host
|
|
2
2
|
|
|
3
|
-
The Ceal Host
|
|
3
|
+
The nested Ceal Host payload selector for supported platforms. It is installed by `@corca-org/ceal` and intentionally registers no global command.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Install `@corca-org/ceal` to receive the sole global `ceal-host` launcher. A machine migrating from an older direct installation removes this package registration without running lifecycle uninstall, then installs `@corca-org/ceal` and uses its launcher to repair the existing activation.
|
package/bin/ceal-host
CHANGED
|
Binary file
|
|
@@ -110,11 +110,28 @@ var client_wire_contract_default = {
|
|
|
110
110
|
],
|
|
111
111
|
bare_document_fields: [
|
|
112
112
|
"invocation",
|
|
113
|
-
"
|
|
113
|
+
"required_action_sequence",
|
|
114
|
+
"entrypoints",
|
|
114
115
|
"common_concepts",
|
|
115
116
|
"operations",
|
|
116
117
|
"catalog_revision"
|
|
117
118
|
],
|
|
119
|
+
prompt_field: "prompt",
|
|
120
|
+
prompt_schema_version: "ceal.prompt.v1",
|
|
121
|
+
focused_prompt_document_fields: [
|
|
122
|
+
"catalog_revision",
|
|
123
|
+
"prompt"
|
|
124
|
+
],
|
|
125
|
+
focused_prompt_continuation_document_fields: [
|
|
126
|
+
"catalog_revision",
|
|
127
|
+
"remaining_work",
|
|
128
|
+
"prompt"
|
|
129
|
+
],
|
|
130
|
+
discovery_command: "discovery",
|
|
131
|
+
discovery_manifest_schema_version: "ceal.discovery_manifest.v1",
|
|
132
|
+
discovery_manifest_document_fields: [
|
|
133
|
+
"discovery_manifest"
|
|
134
|
+
],
|
|
118
135
|
exit_code_max: 125,
|
|
119
136
|
bare_document_max_bytes: 65536,
|
|
120
137
|
complete_max_bytes: 66019,
|
|
@@ -141,8 +158,15 @@ var CEAL_VERIFIED_ARTIFACT_MAX_BYTES = artifact.max_bytes;
|
|
|
141
158
|
var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_MAX_BYTES = artifact.envelope_max_bytes;
|
|
142
159
|
var CEAL_COMMAND_REQUEST_SCHEMA_VERSION = request.schema_version;
|
|
143
160
|
var CEAL_COMMAND_REQUEST_MAX_BYTES = request.absolute_transport_max_bytes;
|
|
144
|
-
var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_FIELDS = response.bare_document_fields;
|
|
145
161
|
var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_MAX_BYTES = response.bare_document_max_bytes;
|
|
162
|
+
var CEAL_COMMAND_RESPONSE_PROMPT_FIELD = response.prompt_field;
|
|
163
|
+
var CEAL_COMMAND_RESPONSE_PROMPT_SCHEMA_VERSION = response.prompt_schema_version;
|
|
164
|
+
var CEAL_COMMAND_RESPONSE_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.bare_document_fields, response.prompt_field]);
|
|
165
|
+
var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_document_fields]);
|
|
166
|
+
var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_CONTINUATION_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_continuation_document_fields]);
|
|
167
|
+
var CEAL_COMMAND_RESPONSE_DISCOVERY_COMMAND = response.discovery_command;
|
|
168
|
+
var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_SCHEMA_VERSION = response.discovery_manifest_schema_version;
|
|
169
|
+
var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_DOCUMENT_FIELDS = Object.freeze([...response.discovery_manifest_document_fields]);
|
|
146
170
|
var CEAL_COMMAND_RESPONSE_MAX_BYTES = response.absolute_transport_max_bytes;
|
|
147
171
|
|
|
148
172
|
// packages/ceal-client-protocol/src/vocabulary.ts
|
|
@@ -178,7 +202,7 @@ var CEAL_OPERATION_RECOVERY_KINDS = vocabulary(["none", "reconcile", "compensate
|
|
|
178
202
|
var CEAL_OPERATION_RECOVERY_STATUSES = vocabulary(["not_started", "active", "completed"]);
|
|
179
203
|
var CEAL_OPERATION_PROVIDER_READBACK_AVAILABILITY = vocabulary(["not_started", "not_applicable", "not_available", "pending", "available"]);
|
|
180
204
|
var CEAL_OPERATION_OFFERED_HANDOFF_STATES = vocabulary(["accepted", "rejected", "unknown"]);
|
|
181
|
-
var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "
|
|
205
|
+
var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]);
|
|
182
206
|
var CEAL_OPERATION_APPROVAL_DISPOSITIONS = vocabulary([
|
|
183
207
|
"approval_not_required_by_policy",
|
|
184
208
|
"interactive_pending",
|
|
@@ -193,6 +217,8 @@ var CEAL_CAPABILITY_READINESS_VALUES = vocabulary(["ready", "degraded", "unavail
|
|
|
193
217
|
var CEAL_TARGET_REQUIREMENTS = vocabulary(["required", "optional", "none"]);
|
|
194
218
|
var CEAL_AUDIT_OUTCOMES = vocabulary(["succeeded", "denied", "failed"]);
|
|
195
219
|
var CEAL_GATEWAY_PROVIDER_STEP_OUTCOMES = vocabulary(["completed", "rejected", "throttled", "failed"]);
|
|
220
|
+
var CEAL_GATEWAY_READ_REUSE_DISPOSITIONS = vocabulary(["response_cache_hit", "corpus_hit", "corpus_hit_after_revalidation", "corpus_partial_provider_supplement", "provider_direct", "provider_continuation", "reuse_unavailable"]);
|
|
221
|
+
var CEAL_GATEWAY_READ_REUSE_UNAVAILABLE_REASONS = vocabulary(["not_reported", "storage_unavailable", "coverage_incomplete", "freshness_refresh_required", "not_reusable", "bypassed"]);
|
|
196
222
|
var CEAL_POLICY_DECISIONS = vocabulary(["allowed", "denied", "not_evaluated"]);
|
|
197
223
|
var CEAL_CONNECTOR_ROUTE_PHASES = vocabulary(["scope_observation", "target_selection", "route_resolution"]);
|
|
198
224
|
var CEAL_CONNECTOR_ROUTE_CAUSES = vocabulary(["provider_throttled", "provider_unavailable", "binding_invalid", "scope_limit_exceeded"]);
|
|
@@ -465,8 +491,10 @@ function requireIsoTimestamp(value, message) {
|
|
|
465
491
|
var JSON_DESCRIPTION_CONTROL_CHARACTER = new RegExp("\\p{Cc}", "u");
|
|
466
492
|
|
|
467
493
|
// packages/ceal-client-protocol/src/operation-contract-validation.ts
|
|
468
|
-
var CEAL_OPERATION_AUTHORITY_POLICY_KEYS = Object.freeze(["
|
|
494
|
+
var CEAL_OPERATION_AUTHORITY_POLICY_KEYS = Object.freeze(["access_group", "instance_binding", "target", "admission_recheck"]);
|
|
469
495
|
var MAX_OPERATION_INPUT_RESOLVER_BINDINGS = 96;
|
|
496
|
+
var CEAL_OPERATION_DESCRIPTOR_REQUIRED_ENVELOPE_KEYS = Object.freeze(["schema_version", "id", "input_contract", "result_contract", "policy"]);
|
|
497
|
+
var CEAL_OPERATION_DESCRIPTOR_OPTIONAL_ENVELOPE_KEYS = Object.freeze(["input_resolution", "summary"]);
|
|
470
498
|
var CEAL_OPERATION_RESULT_KEYS = vocabulary(["ok", "operation_id", "operation_receipt", "schema_version", "value"]);
|
|
471
499
|
var CEAL_OPERATION_COMPACT_RESULT_KEYS = vocabulary(["ok", "operation_evidence", "operation_id", "schema_version", "value"]);
|
|
472
500
|
|
|
@@ -540,6 +568,7 @@ var CEAL_SCHEMA_LITERALS = [
|
|
|
540
568
|
"ceal.operation_descriptor.v1",
|
|
541
569
|
"ceal.operation_error.v1",
|
|
542
570
|
"ceal.operation_failure.v1",
|
|
571
|
+
"ceal.operation_failure.compact.v1",
|
|
543
572
|
"ceal.operation_receipt.v1",
|
|
544
573
|
"ceal.operation_result.v1",
|
|
545
574
|
"ceal.operation_result.compact.v1",
|
|
@@ -565,17 +594,16 @@ var CEAL_BOUNDED_SERIES_CATALOG = Object.freeze({
|
|
|
565
594
|
engagement_signal: (root) => join(root, "runtime-state", "slack-feedback.jsonl"),
|
|
566
595
|
runtime_error: (root) => join(root, "runtime-state", "runtime-errors.jsonl"),
|
|
567
596
|
turn_bridge_request: (root) => join(root, ".ceal", "turn-bridge", "requests.jsonl"),
|
|
568
|
-
channel_log: (root) => join(root, "log.jsonl"),
|
|
569
597
|
thread_run_events: (root) => join(root, "run-events.jsonl"),
|
|
570
598
|
bounded_store_sidecar: (root) => `${root}.jsonl`,
|
|
571
599
|
gateway_audit_archive: (root) => `${root}.jsonl`,
|
|
572
600
|
gateway_capability_audit: (root) => join(root, "capability-audit.jsonl"),
|
|
573
601
|
gateway_retrieval_waste_partition: (root) => `${root}.jsonl`,
|
|
574
602
|
gateway_access_policy_publication: (root) => join(root, "access-policy-publications.jsonl"),
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
603
|
+
gateway_access_group_connector_control_audit: (root) => `${root}.audit.jsonl`,
|
|
604
|
+
gateway_access_group_connector_scope_audit: (root) => join(root, "profile-connector-scope-audit.jsonl"),
|
|
605
|
+
gateway_access_group_connector_activity_scope_audit: (root) => join(root, "profile-connector-activity-scope-audit.jsonl"),
|
|
606
|
+
gateway_access_group_connector_readiness_audit: (root) => join(root, "profile-connector-readiness.audit.jsonl"),
|
|
579
607
|
gateway_organization_audit_ledger: (root) => join(root, "organization-ledger.jsonl"),
|
|
580
608
|
gateway_personal_client_audit: (root) => join(root, "audit.jsonl"),
|
|
581
609
|
gateway_personal_client_access_audit: (root) => join(root, "access-audit.jsonl"),
|
|
@@ -626,12 +654,6 @@ var CEAL_AGENT_SESSION_COMMIT_KEYS = vocabulary(["attempt_ref", "expected_sessio
|
|
|
626
654
|
// packages/ceal-client-protocol/src/operation-next-actions.ts
|
|
627
655
|
var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
|
|
628
656
|
"select_did_you_mean",
|
|
629
|
-
// The graph, not the argument list, is what the caller must change: the
|
|
630
|
-
// resolver that owns this input has no producing node upstream, and no edit
|
|
631
|
-
// to the invocation can conjure one. `resolver_dependency_absent` carried no
|
|
632
|
-
// remedy at all rather than borrow a word that means something else, so the
|
|
633
|
-
// scorer read a fully-diagnosed, caller-fixable refusal as a failed run.
|
|
634
|
-
"request.graph.append",
|
|
635
657
|
"choose_new_output_path",
|
|
636
658
|
"choose_new_idempotency_key",
|
|
637
659
|
"restart_search",
|
|
@@ -683,8 +705,6 @@ var NON_REMEDY_NEXT_ACTION_VALUES = [
|
|
|
683
705
|
"reconcile_occurrence",
|
|
684
706
|
"reduce_request_size",
|
|
685
707
|
"repair_or_adopt_session",
|
|
686
|
-
"request.effect_approval.read",
|
|
687
|
-
"request.run",
|
|
688
708
|
"retry",
|
|
689
709
|
// The owner -- a correlation hook, an approval hook -- is not serving right
|
|
690
710
|
// now. The caller changes nothing and the same call succeeds once the owner
|
|
@@ -781,12 +801,12 @@ var CEAL_REQUEST_JSON_SCHEMA = {
|
|
|
781
801
|
additionalProperties: false,
|
|
782
802
|
properties: {
|
|
783
803
|
instance_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
784
|
-
|
|
804
|
+
access_group_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
785
805
|
principal_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
786
806
|
execution_subject_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
787
807
|
authority_revision_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
|
|
788
808
|
},
|
|
789
|
-
required: ["instance_ref", "
|
|
809
|
+
required: ["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]
|
|
790
810
|
},
|
|
791
811
|
prompt_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
792
812
|
host_session_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
@@ -918,7 +938,7 @@ var CEAL_HOST_OBSERVATION_KINDS = vocabulary(["prompt", "session", "turn", "mode
|
|
|
918
938
|
function isCealHostPromptObservationValue(value) {
|
|
919
939
|
return isOperationRecord(value) && Object.keys(value).length === 1 && isCealDigest(value.body_sha256);
|
|
920
940
|
}
|
|
921
|
-
var HOST_RESERVED_KEY = /^(?:admission|approval|audit|authorization|cancellation|capability|effect|grant|occurrence|operation|policy|profile|provider_readback|receipt|reconciliation|replay|target|write_request)(?:_|$)/iu;
|
|
941
|
+
var HOST_RESERVED_KEY = /^(?:access_group|admission|approval|audit|authorization|cancellation|capability|effect|grant|occurrence|operation|policy|profile|provider_readback|receipt|reconciliation|replay|target|write_request)(?:_|$)/iu;
|
|
922
942
|
function assertHostObservationValue(value, kind) {
|
|
923
943
|
if (value === void 0) invalid("Ceal Host observation value is invalid.");
|
|
924
944
|
if (kind === "prompt" && !isCealHostPromptObservationValue(value)) invalid("Ceal Host prompt observation must contain only its body digest.");
|
|
@@ -938,6 +958,14 @@ function inspectHostKeys(value) {
|
|
|
938
958
|
}
|
|
939
959
|
}
|
|
940
960
|
|
|
961
|
+
// packages/ceal-client-protocol/src/host-prompt-ref.ts
|
|
962
|
+
var CEAL_HOST_PROMPT_DIGEST_PATTERN = "^[a-f0-9]{64}$";
|
|
963
|
+
var PROMPT_DIGEST = new RegExp(CEAL_HOST_PROMPT_DIGEST_PATTERN, "u");
|
|
964
|
+
function hostProducerPromptRef(promptSha256) {
|
|
965
|
+
if (!PROMPT_DIGEST.test(promptSha256)) throw new TypeError("Canonical Host prompt digest is invalid.");
|
|
966
|
+
return `ceal-host-prompt:${promptSha256}`;
|
|
967
|
+
}
|
|
968
|
+
|
|
941
969
|
// packages/ceal-client-protocol/src/request-effect-approval.ts
|
|
942
970
|
var CEAL_EFFECT_APPROVAL_DECISION_CHECK_PHRASES = Object.freeze([
|
|
943
971
|
"observed after this approval was raised and before it expires",
|
|
@@ -953,6 +981,12 @@ var OWNER_WRITE_STATES = Object.freeze(["attempt_started", "provider_acknowledge
|
|
|
953
981
|
var OWNER_EFFECT_STATES = Object.freeze(["none", "applied", "failed", "unknown", "reconciled"]);
|
|
954
982
|
var OWNER_RECEIPT_STATES = Object.freeze(["pending", "available", "failed", "unknown", "reconciled"]);
|
|
955
983
|
|
|
984
|
+
// packages/ceal-client-protocol/src/thread-excerpt.ts
|
|
985
|
+
var CEAL_THREAD_RECENT_WINDOW = 6;
|
|
986
|
+
var CEAL_THREAD_LAST_APP_MESSAGES_WINDOW = 3;
|
|
987
|
+
var CEAL_THREAD_OLDER_SUMMARY_WINDOW = 4;
|
|
988
|
+
var CEAL_FED_THREAD_MESSAGE_LIMIT = CEAL_THREAD_RECENT_WINDOW + CEAL_THREAD_OLDER_SUMMARY_WINDOW + CEAL_THREAD_LAST_APP_MESSAGES_WINDOW;
|
|
989
|
+
|
|
956
990
|
// packages/ceal-client-protocol/src/request-graph-readiness.ts
|
|
957
991
|
var REQUEST_GRAPH_PRODUCER_TO_APPEND_SCHEMA = {
|
|
958
992
|
type: "object",
|
|
@@ -1032,6 +1066,13 @@ var CEAL_REQUEST_GRAPH_NODE_PREPARE_READINESS_JSON_SCHEMA = {
|
|
|
1032
1066
|
var REQUIRED_FIELDS = Object.freeze(["schema_version", "operation_id", "local_path", "content_json_pointer", "size_bytes", "sha256", "read_argv"]);
|
|
1033
1067
|
var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS, "local_result_root", "model_disclosure"]);
|
|
1034
1068
|
|
|
1069
|
+
// packages/ceal-client-protocol/src/session-start-affordance.ts
|
|
1070
|
+
var CEAL_SESSION_ENTRY_INVOCATION = "ceal";
|
|
1071
|
+
var CEAL_LINK_RESOURCE_PRECEDENCE = `When the user asks to use Ceal or provides a link to information that may be available through installed organizational capabilities, run bare \`${CEAL_SESSION_ENTRY_INVOCATION}\`. The Host supplies the current user prompt without exposing it to the client command, and the Gateway returns the applicable entry in that one response. Treat a supplied link as a candidate Ceal resource rather than a public web-search target. Reach for a generic web fetch or web search only when the Gateway offered nothing.`;
|
|
1072
|
+
|
|
1073
|
+
// packages/ceal-client-protocol/src/discovery-manifest.ts
|
|
1074
|
+
var CEAL_DISCOVERY_MANIFEST_CONNECTOR_KINDS = vocabulary(["github", "google-workspace", "notion", "slack"]);
|
|
1075
|
+
|
|
1035
1076
|
// packages/ceal-client-protocol/src/conversation-contracts.ts
|
|
1036
1077
|
var CEAL_APPROVAL_POLICY_KINDS = vocabulary(["requester_only", "named_users", "role_based"]);
|
|
1037
1078
|
var CEAL_APPROVAL_TARGET_KINDS = vocabulary([
|
|
@@ -1248,7 +1289,7 @@ var CEAL_PRESENTATION_INTENTS = vocabulary(["progress", ...CEAL_FINAL_PRESENTATI
|
|
|
1248
1289
|
|
|
1249
1290
|
// packages/ceal-client-protocol/src/personal-client-vocabulary.ts
|
|
1250
1291
|
var CEAL_PERSONAL_CLIENT_BINDING_KEYS = vocabulary([
|
|
1251
|
-
"
|
|
1292
|
+
"access_group_ref",
|
|
1252
1293
|
"membership_ref",
|
|
1253
1294
|
"registration_ref",
|
|
1254
1295
|
"client_ref",
|
|
@@ -1263,7 +1304,8 @@ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
|
|
|
1263
1304
|
"refresh_replayed",
|
|
1264
1305
|
"refresh_revoked",
|
|
1265
1306
|
"authority_replaced",
|
|
1266
|
-
"refresh_recovery_unavailable"
|
|
1307
|
+
"refresh_recovery_unavailable",
|
|
1308
|
+
"refresh_recovery_expired"
|
|
1267
1309
|
]);
|
|
1268
1310
|
|
|
1269
1311
|
// packages/ceal-client-protocol/src/device-enrollment.ts
|
|
@@ -1396,7 +1438,6 @@ var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
|
|
|
1396
1438
|
var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
|
|
1397
1439
|
var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
|
|
1398
1440
|
var SAFE_REF2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
1399
|
-
var DIGEST2 = /^[a-f0-9]{64}$/u;
|
|
1400
1441
|
var PRODUCERS = /* @__PURE__ */ new Set(["codex", "claude"]);
|
|
1401
1442
|
var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "user_input", "turn_terminal", "producer_status"];
|
|
1402
1443
|
var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
|
|
@@ -1437,10 +1478,6 @@ function decodeHostProducerFrame(input) {
|
|
|
1437
1478
|
validateFrame(value);
|
|
1438
1479
|
return value;
|
|
1439
1480
|
}
|
|
1440
|
-
function hostProducerPromptRef(promptSha256) {
|
|
1441
|
-
if (!DIGEST2.test(promptSha256)) throw new TypeError("Canonical Host prompt digest is invalid.");
|
|
1442
|
-
return `ceal-host-prompt:${promptSha256}`;
|
|
1443
|
-
}
|
|
1444
1481
|
function validateFrame(value) {
|
|
1445
1482
|
if (!record2(value)) throw new HostProducerFrameError("invalid_frame_shape");
|
|
1446
1483
|
if (value.schema_version !== HOST_PRODUCER_FRAME_SCHEMA) throw new HostProducerFrameError("unsupported_frame_schema", `unsupported_frame_schema: ${refusalFact("schema_version", value.schema_version, HOST_PRODUCER_FRAME_SCHEMA)}`);
|
|
@@ -1621,12 +1658,19 @@ var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
|
|
|
1621
1658
|
|
|
1622
1659
|
// host/relay/src/relay-admission-store.ts
|
|
1623
1660
|
var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
|
|
1661
|
+
var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
|
|
1662
|
+
var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
|
|
1624
1663
|
|
|
1625
1664
|
// host/relay/src/relay-request-binding-store.ts
|
|
1626
1665
|
var MAX_STATE_BYTES = 8 * 1024 * 1024;
|
|
1627
1666
|
|
|
1628
1667
|
// host/relay/src/relay-ipc.ts
|
|
1629
1668
|
import { createConnection, createServer } from "node:net";
|
|
1669
|
+
|
|
1670
|
+
// host/relay/src/current-prompt-custody.ts
|
|
1671
|
+
var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
|
|
1672
|
+
|
|
1673
|
+
// host/relay/src/relay-ipc.ts
|
|
1630
1674
|
var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
|
|
1631
1675
|
"schema_version",
|
|
1632
1676
|
"producer_id",
|
|
@@ -1643,6 +1687,8 @@ var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
|
|
|
1643
1687
|
"host_input_ref"
|
|
1644
1688
|
]);
|
|
1645
1689
|
var HOST_RELAY_IPC_RESPONSE_SCHEMA = "ceal.host_relay_admission.v1";
|
|
1690
|
+
var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
|
|
1691
|
+
var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
|
|
1646
1692
|
var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
|
|
1647
1693
|
var HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES = 4096;
|
|
1648
1694
|
var HostRelayIpcError = class extends Error {
|
|
@@ -1665,22 +1711,42 @@ var HostRelayIpcAdmissionPort = class {
|
|
|
1665
1711
|
return { code: response2.code, admitted_through_sequence: response2.admitted_through_sequence, delivered_through_sequence: response2.delivered_through_sequence };
|
|
1666
1712
|
}
|
|
1667
1713
|
};
|
|
1714
|
+
var HostRelayCurrentPromptPort = class {
|
|
1715
|
+
endpoint;
|
|
1716
|
+
timeout_ms;
|
|
1717
|
+
constructor(endpoint, timeoutMs = 5e3) {
|
|
1718
|
+
this.endpoint = endpoint;
|
|
1719
|
+
this.timeout_ms = timeoutMs;
|
|
1720
|
+
}
|
|
1721
|
+
async register(input) {
|
|
1722
|
+
const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA, ...input };
|
|
1723
|
+
const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
|
|
1724
|
+
if (response2.status !== "registered") throw new HostRelayIpcError("relay_unavailable", response2.status);
|
|
1725
|
+
}
|
|
1726
|
+
};
|
|
1668
1727
|
function submitHostProducerFrame(endpoint, frame, timeoutMs = 5e3) {
|
|
1669
1728
|
return exchange(endpoint, encodeHostProducerFrame(frame), timeoutMs, decodeResponseBuffer);
|
|
1670
1729
|
}
|
|
1671
|
-
function exchange(endpoint, encoded, timeoutMs, decode) {
|
|
1730
|
+
function exchange(endpoint, encoded, timeoutMs, decode, signal) {
|
|
1672
1731
|
return new Promise((resolve, reject) => {
|
|
1673
1732
|
const socket = createConnection(endpoint);
|
|
1674
1733
|
let buffer = Buffer.alloc(0);
|
|
1675
1734
|
let settled = false;
|
|
1735
|
+
const aborted = () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC was cancelled."));
|
|
1676
1736
|
const finish = (error, response2) => {
|
|
1677
1737
|
if (settled) return;
|
|
1678
1738
|
settled = true;
|
|
1739
|
+
signal?.removeEventListener("abort", aborted);
|
|
1679
1740
|
socket.destroy();
|
|
1680
1741
|
if (error !== null) reject(error);
|
|
1681
1742
|
else if (response2 !== void 0) resolve(response2);
|
|
1682
1743
|
};
|
|
1683
|
-
socket.setTimeout(timeoutMs, () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC timed out.")));
|
|
1744
|
+
if (timeoutMs !== void 0) socket.setTimeout(timeoutMs, () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC timed out.")));
|
|
1745
|
+
if (signal?.aborted === true) {
|
|
1746
|
+
aborted();
|
|
1747
|
+
return;
|
|
1748
|
+
}
|
|
1749
|
+
signal?.addEventListener("abort", aborted, { once: true });
|
|
1684
1750
|
socket.once("error", () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC is unavailable.")));
|
|
1685
1751
|
socket.once("connect", () => socket.write(encoded));
|
|
1686
1752
|
socket.on("data", (chunk) => {
|
|
@@ -1733,6 +1799,34 @@ function decodeResponseBuffer(buffer) {
|
|
|
1733
1799
|
if (buffer.length !== length + HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC returned trailing bytes: ${refusalFacts([{ name: "declared_bytes", value: length, expected: `the received message length minus ${HOST_RELAY_IPC_LENGTH_BYTES}` }, { name: "received_bytes", value: buffer.byteLength, expected: `exactly ${length + HOST_RELAY_IPC_LENGTH_BYTES}` }])}.`);
|
|
1734
1800
|
return decodeHostRelayIpcResponse(buffer);
|
|
1735
1801
|
}
|
|
1802
|
+
function decodeCurrentPromptResponseBuffer(buffer) {
|
|
1803
|
+
const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES);
|
|
1804
|
+
if (value === null) return null;
|
|
1805
|
+
if (!record3(value) || !exactKeys2(value, ["schema_version", "status"]) || value.schema_version !== HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA || value.status !== "registered" && value.status !== "current_prompt_unavailable") throw new HostRelayIpcError("relay_unavailable");
|
|
1806
|
+
return { schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status: value.status };
|
|
1807
|
+
}
|
|
1808
|
+
function decodeLengthPrefixedJson(input, maximum) {
|
|
1809
|
+
if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
|
|
1810
|
+
const length = input.readUInt32BE(0);
|
|
1811
|
+
if (length === 0 || length > maximum) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC message length is invalid: ${refusalFact("declared_bytes", length, `between 1 and ${maximum}`)}.`);
|
|
1812
|
+
if (input.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
|
|
1813
|
+
if (input.length !== length + HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC message has trailing bytes: ${refusalFacts([{ name: "declared_bytes", value: length, expected: `the received message length minus ${HOST_RELAY_IPC_LENGTH_BYTES}` }, { name: "received_bytes", value: input.byteLength, expected: `exactly ${length + HOST_RELAY_IPC_LENGTH_BYTES}` }])}.`);
|
|
1814
|
+
try {
|
|
1815
|
+
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
|
|
1816
|
+
} catch {
|
|
1817
|
+
throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC message is invalid.");
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
function encodeLengthPrefixed(value) {
|
|
1821
|
+
const body = Buffer.from(JSON.stringify(value), "utf8");
|
|
1822
|
+
const output = Buffer.allocUnsafe(body.length + HOST_RELAY_IPC_LENGTH_BYTES);
|
|
1823
|
+
output.writeUInt32BE(body.length, 0);
|
|
1824
|
+
body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
|
|
1825
|
+
return output;
|
|
1826
|
+
}
|
|
1827
|
+
function exactKeys2(value, keys) {
|
|
1828
|
+
return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
1829
|
+
}
|
|
1736
1830
|
|
|
1737
1831
|
// host/invocation-context.ts
|
|
1738
1832
|
var HOST_INVOCATION_IDENTITY_KEYS = ["host_session_ref", "host_turn_ref", "host_source_ref"];
|
|
@@ -1741,7 +1835,7 @@ function invocationContextKey(identity) {
|
|
|
1741
1835
|
return cealRequestSha256({ host_source_ref: identity.host_source_ref, host_session_ref: identity.host_session_ref });
|
|
1742
1836
|
}
|
|
1743
1837
|
function hasHostInvocationIdentityKeys(value) {
|
|
1744
|
-
return
|
|
1838
|
+
return exactKeys3(value, HOST_INVOCATION_IDENTITY_KEYS);
|
|
1745
1839
|
}
|
|
1746
1840
|
function hasHostInvocationContextKeys(value, optional = []) {
|
|
1747
1841
|
return requiredKeys(value, HOST_INVOCATION_CONTEXT_REQUIRED_KEYS, optional);
|
|
@@ -1757,7 +1851,7 @@ function invocationContextFromTurn(identity, promptRef, expiresAt, descriptor) {
|
|
|
1757
1851
|
descriptor.validate(context);
|
|
1758
1852
|
return Object.freeze(context);
|
|
1759
1853
|
}
|
|
1760
|
-
function
|
|
1854
|
+
function exactKeys3(value, keys) {
|
|
1761
1855
|
const actual = Object.keys(value);
|
|
1762
1856
|
return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key)) && actual.every((key) => keys.includes(key));
|
|
1763
1857
|
}
|
|
@@ -1969,6 +2063,8 @@ var ClaudeHookAdapter = class {
|
|
|
1969
2063
|
this.store = new ClaudeOutboxStore(options.outbox_dir);
|
|
1970
2064
|
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
1971
2065
|
this.optionsSourceRef = options.host_source_ref ?? "claude-host:local";
|
|
2066
|
+
this.producerInstallationRef = options.producer_installation_ref;
|
|
2067
|
+
this.registerCurrentPrompt = options.register_current_prompt;
|
|
1972
2068
|
}
|
|
1973
2069
|
async handle(event, raw) {
|
|
1974
2070
|
let input;
|
|
@@ -1981,6 +2077,10 @@ var ClaudeHookAdapter = class {
|
|
|
1981
2077
|
const sessionRef = claudeLocalSessionRef(input.session_id);
|
|
1982
2078
|
const turnRef = input.prompt_id === void 0 ? void 0 : claudeLocalTurnRef(input.session_id, input.prompt_id);
|
|
1983
2079
|
const frames = mapFrames(input, occurredAt);
|
|
2080
|
+
if (input.hook_event_name === "UserPromptSubmit" && turnRef !== void 0 && this.producerInstallationRef !== void 0 && this.registerCurrentPrompt !== void 0) {
|
|
2081
|
+
const promptRef = hostProducerPromptRef(createHash3("sha256").update(input.prompt, "utf8").digest("hex"));
|
|
2082
|
+
await this.registerCurrentPrompt({ producer_id: "claude", producer_installation_ref: this.producerInstallationRef, local_session_ref: sessionRef, local_turn_ref: turnRef, prompt_ref: promptRef, current_prompt: input.prompt, context_expires_at: new Date(Date.parse(occurredAt) + 24 * 60 * 60 * 1e3).toISOString() });
|
|
2083
|
+
}
|
|
1984
2084
|
const batchRef = `claude-batch:${cealRequestSha256({ event, session_ref: sessionRef, turn_ref: turnRef ?? null, occurred_at: occurredAt, frames })}`;
|
|
1985
2085
|
const batch = { schema_version: CLAUDE_OUTBOX_SCHEMA, batch_ref: batchRef, hook_event: event, local_session_ref: sessionRef, ...turnRef === void 0 ? {} : { local_turn_ref: turnRef }, occurred_at: occurredAt, frames };
|
|
1986
2086
|
await this.store.put(batch);
|
|
@@ -2001,6 +2101,8 @@ var ClaudeHookAdapter = class {
|
|
|
2001
2101
|
await this.store.activateInvocationContext(identity, hostProducerPromptRef(promptValue.body_sha256), expiresAt, input.cwd);
|
|
2002
2102
|
}
|
|
2003
2103
|
optionsSourceRef;
|
|
2104
|
+
producerInstallationRef;
|
|
2105
|
+
registerCurrentPrompt;
|
|
2004
2106
|
};
|
|
2005
2107
|
function mapFrames(input, at) {
|
|
2006
2108
|
if (input.hook_event_name === "SessionStart") return sessionFrames(input, at);
|
|
@@ -2171,12 +2273,6 @@ async function drainClaudeProducerOnce(options) {
|
|
|
2171
2273
|
import { homedir } from "node:os";
|
|
2172
2274
|
import { join as join4 } from "node:path";
|
|
2173
2275
|
|
|
2174
|
-
// host/session-start-affordance.ts
|
|
2175
|
-
var HOST_ENTRY_AFFORDANCE = "When the user asks to use Ceal or provides a link to information that may be available through installed organizational capabilities, first run the bare `ceal` shell command with no arguments; treat that link as a candidate Ceal resource rather than a public web-search target, and let the current Profile capability result supply the exact next steps.";
|
|
2176
|
-
function hostSessionStartEntryAffordance(hostName) {
|
|
2177
|
-
return `${HOST_ENTRY_AFFORDANCE} This text is the Ceal ${hostName} Host's own SessionStart hook running in this ${hostName} session. The Host owns this session's Request identity, and the generic client authenticates each call automatically; follow the required_action_sequence returned by bare \`ceal\`. Never run \`ceal request create\`, and never type, guess, or reuse --host-session-ref, --host-turn-ref, --prompt-ref, or any other session or turn reference.`;
|
|
2178
|
-
}
|
|
2179
|
-
|
|
2180
2276
|
// host/producer-service.ts
|
|
2181
2277
|
import { constants } from "node:fs";
|
|
2182
2278
|
import { lstat as lstat2, open as open3 } from "node:fs/promises";
|
|
@@ -2357,10 +2453,6 @@ var CLAUDE_PRODUCER_DESCRIPTOR = {
|
|
|
2357
2453
|
|
|
2358
2454
|
// host/claude/src/claude-hook-runner.ts
|
|
2359
2455
|
var MAX_STDIN_BYTES = 256 * 1024;
|
|
2360
|
-
var CLAUDE_SESSION_START_ENTRY_AFFORDANCE = hostSessionStartEntryAffordance("Claude");
|
|
2361
|
-
function claudeSessionStartHookOutput() {
|
|
2362
|
-
return { suppressOutput: true, hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: CLAUDE_SESSION_START_ENTRY_AFFORDANCE } };
|
|
2363
|
-
}
|
|
2364
2456
|
async function runClaudeHookFromStdin(event, stdin, options) {
|
|
2365
2457
|
return new ClaudeHookAdapter(options).handle(event, await readStdin(stdin));
|
|
2366
2458
|
}
|
|
@@ -2371,11 +2463,21 @@ function claudeHookEventFromArgs(args) {
|
|
|
2371
2463
|
async function runClaudeHookProcess(args, stdin, options) {
|
|
2372
2464
|
const event = claudeHookEventFromArgs(args);
|
|
2373
2465
|
if (event === null) return 0;
|
|
2374
|
-
|
|
2375
|
-
|
|
2466
|
+
try {
|
|
2467
|
+
const result = await runClaudeHookFromStdin(event, stdin, options);
|
|
2468
|
+
if (result.disposition === "rejected") writeClaudeHookDiagnostic(result);
|
|
2469
|
+
return 0;
|
|
2470
|
+
} catch (error) {
|
|
2471
|
+
writeClaudeHookDiagnostic({ event, disposition: "rejected", reason: error instanceof Error ? error.message.slice(0, 128) : "claude_hook_failed" });
|
|
2472
|
+
return 0;
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
function writeClaudeHookDiagnostic(result) {
|
|
2476
|
+
try {
|
|
2477
|
+
process.stderr.write(`${JSON.stringify({ schema_version: "ceal.claude_sessionstart_diagnostic.v1", event: result.event, disposition: result.disposition, ...result.reason === void 0 ? {} : { reason: result.reason } })}
|
|
2376
2478
|
`);
|
|
2377
|
-
|
|
2378
|
-
|
|
2479
|
+
} catch {
|
|
2480
|
+
}
|
|
2379
2481
|
}
|
|
2380
2482
|
async function runClaudeHookCli() {
|
|
2381
2483
|
const args = process.argv.slice(2);
|
|
@@ -2384,7 +2486,8 @@ async function runClaudeHookCli() {
|
|
|
2384
2486
|
}
|
|
2385
2487
|
async function installedClaudeHookRunnerOptions(args) {
|
|
2386
2488
|
const config = await readHostProducerConfig(CLAUDE_PRODUCER_DESCRIPTOR, parseHostProducerConfigFlag(args));
|
|
2387
|
-
const
|
|
2489
|
+
const port = new HostRelayCurrentPromptPort(config.relay_endpoint, config.ipc_timeout_ms);
|
|
2490
|
+
const options = { outbox_dir: config.outbox_dir, producer_installation_ref: config.producer_installation_ref, register_current_prompt: (input) => port.register(input) };
|
|
2388
2491
|
Object.defineProperty(options, "host_source_ref", { value: config.host_source_ref, enumerable: false });
|
|
2389
2492
|
return options;
|
|
2390
2493
|
}
|