@brightbeamai/chap-coordinator 0.2.8 → 0.2.9
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 +5 -12
- package/dist/{api-CmSvlIqO.d.ts → api-CPEk0V6i.d.ts} +1 -0
- package/dist/{api-C3nkEk-B.d.cts → api-DE78DA0o.d.cts} +1 -0
- package/dist/api.d.cts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/index.cjs +78 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +78 -16
- package/dist/index.js.map +1 -1
- package/dist/methods.cjs.map +1 -1
- package/dist/methods.d.cts +1 -0
- package/dist/methods.d.ts +1 -0
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +3 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as CoordinatorOptions, a as Coordinator } from './api-
|
|
2
|
-
export { b as CoordinatorApi, c as CoordinatorError, d as CredentialVerifier, E as EscalationPolicyFn, H as Handler, I as IdFactory, P as PRIVILEGED_METHODS, R as ReviewDepthPolicyFn, e as RoutingPolicyFn, S as ScittReceiptVerifier, f as ScittSubmitter, T as TokenVerifier, g as call, m as makeApi } from './api-
|
|
1
|
+
import { C as CoordinatorOptions, a as Coordinator } from './api-DE78DA0o.cjs';
|
|
2
|
+
export { b as CoordinatorApi, c as CoordinatorError, d as CredentialVerifier, E as EscalationPolicyFn, H as Handler, I as IdFactory, P as PRIVILEGED_METHODS, R as ReviewDepthPolicyFn, e as RoutingPolicyFn, S as ScittReceiptVerifier, f as ScittSubmitter, T as TokenVerifier, g as call, m as makeApi } from './api-DE78DA0o.cjs';
|
|
3
3
|
export { MethodName, MethodParams, MethodResult, MethodTable } from './methods.cjs';
|
|
4
4
|
export { MemoryStore, Store, WorkspaceRecord } from './storage/store.cjs';
|
|
5
5
|
export { ArtefactId, ArtefactRoutingHints, AuditEntry, AuditListener, Deliberation, DeliberationVote, Envelope, Handoff, HandoffTaskItem, JsonPatchOp, Jwk, KeyRecord, Member, Mode, OverrideArtefact, ParticipantType, ParticipantUri, PauseScope, ReviewDecision, RouteDecisionArtefact, SnapshotArtefact, Task, TaskId, TaskRoutingHints, TaskState, WhisperPrompt, Workspace, WorkspaceId, WorkspaceState, modeLE } from './types.cjs';
|
|
@@ -107,7 +107,7 @@ declare function makeDefaultPolicy(seniorTarget: string): Pick<CoordinatorOption
|
|
|
107
107
|
* happened outside CHAP, wrap it so the audit log carries a faithful,
|
|
108
108
|
* citable record.
|
|
109
109
|
*
|
|
110
|
-
* Spec target: CHAP 0.2. MCP
|
|
110
|
+
* Spec target: CHAP 0.2. MCP 2026-07-28. A2A 1.0.
|
|
111
111
|
*/
|
|
112
112
|
|
|
113
113
|
interface WrapMcpToolCallOptions {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as CoordinatorOptions, a as Coordinator } from './api-
|
|
2
|
-
export { b as CoordinatorApi, c as CoordinatorError, d as CredentialVerifier, E as EscalationPolicyFn, H as Handler, I as IdFactory, P as PRIVILEGED_METHODS, R as ReviewDepthPolicyFn, e as RoutingPolicyFn, S as ScittReceiptVerifier, f as ScittSubmitter, T as TokenVerifier, g as call, m as makeApi } from './api-
|
|
1
|
+
import { C as CoordinatorOptions, a as Coordinator } from './api-CPEk0V6i.js';
|
|
2
|
+
export { b as CoordinatorApi, c as CoordinatorError, d as CredentialVerifier, E as EscalationPolicyFn, H as Handler, I as IdFactory, P as PRIVILEGED_METHODS, R as ReviewDepthPolicyFn, e as RoutingPolicyFn, S as ScittReceiptVerifier, f as ScittSubmitter, T as TokenVerifier, g as call, m as makeApi } from './api-CPEk0V6i.js';
|
|
3
3
|
export { MethodName, MethodParams, MethodResult, MethodTable } from './methods.js';
|
|
4
4
|
export { MemoryStore, Store, WorkspaceRecord } from './storage/store.js';
|
|
5
5
|
export { ArtefactId, ArtefactRoutingHints, AuditEntry, AuditListener, Deliberation, DeliberationVote, Envelope, Handoff, HandoffTaskItem, JsonPatchOp, Jwk, KeyRecord, Member, Mode, OverrideArtefact, ParticipantType, ParticipantUri, PauseScope, ReviewDecision, RouteDecisionArtefact, SnapshotArtefact, Task, TaskId, TaskRoutingHints, TaskState, WhisperPrompt, Workspace, WorkspaceId, WorkspaceState, modeLE } from './types.js';
|
|
@@ -107,7 +107,7 @@ declare function makeDefaultPolicy(seniorTarget: string): Pick<CoordinatorOption
|
|
|
107
107
|
* happened outside CHAP, wrap it so the audit log carries a faithful,
|
|
108
108
|
* citable record.
|
|
109
109
|
*
|
|
110
|
-
* Spec target: CHAP 0.2. MCP
|
|
110
|
+
* Spec target: CHAP 0.2. MCP 2026-07-28. A2A 1.0.
|
|
111
111
|
*/
|
|
112
112
|
|
|
113
113
|
interface WrapMcpToolCallOptions {
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
-
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
1
|
// src/canonical.ts
|
|
9
2
|
import { createHash } from "crypto";
|
|
10
3
|
var ZERO_HASH = "sha256:" + "0".repeat(64);
|
|
@@ -169,12 +162,7 @@ var IdFactory = class {
|
|
|
169
162
|
return this.counter * 0x9E3779B97F4A7C15n & (1n << 80n) - 1n;
|
|
170
163
|
}
|
|
171
164
|
const buf = new Uint8Array(10);
|
|
172
|
-
|
|
173
|
-
crypto.getRandomValues(buf);
|
|
174
|
-
} else {
|
|
175
|
-
const nodeCrypto = __require("crypto");
|
|
176
|
-
buf.set(nodeCrypto.randomBytes(10));
|
|
177
|
-
}
|
|
165
|
+
crypto.getRandomValues(buf);
|
|
178
166
|
let n = 0n;
|
|
179
167
|
for (const b of buf) n = n << 8n | BigInt(b);
|
|
180
168
|
return n;
|
|
@@ -1517,6 +1505,16 @@ function registerSecuritySigned(coord) {
|
|
|
1517
1505
|
for (const f of ["target_uri", "kid"]) {
|
|
1518
1506
|
if (!(f in p)) return { error: rpcError(E.PARAMS, `Missing field: ${f}`) };
|
|
1519
1507
|
}
|
|
1508
|
+
const sender = p.from;
|
|
1509
|
+
if (sender !== p.target_uri) {
|
|
1510
|
+
const caller = sender ? ws.members.get(sender) : void 0;
|
|
1511
|
+
if (!caller || caller.role !== "admin") {
|
|
1512
|
+
return { error: rpcError(
|
|
1513
|
+
E.NOT_AUTHORISED,
|
|
1514
|
+
"Revoking another member's key requires the admin role"
|
|
1515
|
+
) };
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1520
1518
|
const member = ws.members.get(p.target_uri);
|
|
1521
1519
|
if (!member) return { error: rpcError(E.SIG_KEY_NOT_FOUND, `Unknown target: ${p.target_uri}`) };
|
|
1522
1520
|
const key = member.keys.find((k) => k.kid === p.kid);
|
|
@@ -1608,7 +1606,8 @@ function registerWhisper(coord) {
|
|
|
1608
1606
|
prompt.answer_option = answerOption;
|
|
1609
1607
|
prompt.answer_text = answerText;
|
|
1610
1608
|
prompt.comment = p.comment;
|
|
1611
|
-
|
|
1609
|
+
p.task_id = prompt.task_id;
|
|
1610
|
+
return { result: { answered: true, whisper_id: prompt.id, task_id: prompt.task_id } };
|
|
1612
1611
|
});
|
|
1613
1612
|
coord.checkWhisperLapses = (workspaceId, now) => {
|
|
1614
1613
|
const ws = coord.workspaces.get(workspaceId);
|
|
@@ -1632,6 +1631,11 @@ function registerWhisper(coord) {
|
|
|
1632
1631
|
ts: coord.now(),
|
|
1633
1632
|
kind: "whisper_lapsed",
|
|
1634
1633
|
whisper_id: prompt.id,
|
|
1634
|
+
// Carry the task so a task-filtered audit.read surfaces the
|
|
1635
|
+
// lapse. A lapsed whisper applies its default with no human
|
|
1636
|
+
// input, so it is the case most in need of being visible on
|
|
1637
|
+
// the task's thread.
|
|
1638
|
+
task_id: prompt.task_id,
|
|
1635
1639
|
default_applied: prompt.default_if_lapsed
|
|
1636
1640
|
}
|
|
1637
1641
|
};
|
|
@@ -1833,6 +1837,7 @@ var Coordinator = class {
|
|
|
1833
1837
|
mode_ceiling: ws.mode_ceiling,
|
|
1834
1838
|
routing_policy_uri: ws.routing_policy_uri,
|
|
1835
1839
|
step_up_window_sec: ws.step_up_window_sec,
|
|
1840
|
+
min_acr: ws.min_acr,
|
|
1836
1841
|
members: Array.from(ws.members.values()),
|
|
1837
1842
|
tasks: Array.from(ws.tasks.values()),
|
|
1838
1843
|
overrides: Array.from(ws.overrides.values()),
|
|
@@ -1841,6 +1846,7 @@ var Coordinator = class {
|
|
|
1841
1846
|
handoffs: Array.from(ws.handoffs.values()),
|
|
1842
1847
|
snapshots: Array.from(ws.snapshots.values()),
|
|
1843
1848
|
route_decisions: Array.from(ws.route_decisions.values()),
|
|
1849
|
+
idempotency_keys: ws.idempotency_keys,
|
|
1844
1850
|
audit: ws.audit,
|
|
1845
1851
|
chain_head: ws.chain_head,
|
|
1846
1852
|
chain_enabled: ws.chain_enabled
|
|
@@ -1863,6 +1869,7 @@ var Coordinator = class {
|
|
|
1863
1869
|
mode_ceiling: w.mode_ceiling ?? "production",
|
|
1864
1870
|
routing_policy_uri: w.routing_policy_uri,
|
|
1865
1871
|
step_up_window_sec: w.step_up_window_sec ?? 300,
|
|
1872
|
+
min_acr: w.min_acr,
|
|
1866
1873
|
members: /* @__PURE__ */ new Map(),
|
|
1867
1874
|
tasks: /* @__PURE__ */ new Map(),
|
|
1868
1875
|
overrides: /* @__PURE__ */ new Map(),
|
|
@@ -1871,6 +1878,7 @@ var Coordinator = class {
|
|
|
1871
1878
|
handoffs: /* @__PURE__ */ new Map(),
|
|
1872
1879
|
snapshots: /* @__PURE__ */ new Map(),
|
|
1873
1880
|
route_decisions: /* @__PURE__ */ new Map(),
|
|
1881
|
+
idempotency_keys: w.idempotency_keys ?? {},
|
|
1874
1882
|
audit: w.audit ?? [],
|
|
1875
1883
|
chain_head: w.chain_head,
|
|
1876
1884
|
chain_enabled: !!w.chain_enabled
|
|
@@ -1909,6 +1917,16 @@ var Coordinator = class {
|
|
|
1909
1917
|
if (this.options.requireSignatures && method !== "participant.join" && method !== "workspace.create") {
|
|
1910
1918
|
const sigErr = this.verifySignature(envelope);
|
|
1911
1919
|
if (sigErr) return reply(envelope, { error: sigErr });
|
|
1920
|
+
if (method === "participant.rotate_key") {
|
|
1921
|
+
const signingKid = envelope.sig.split(":")[1];
|
|
1922
|
+
const oldKid = params.old_kid;
|
|
1923
|
+
if (oldKid !== void 0 && signingKid !== oldKid) {
|
|
1924
|
+
return reply(envelope, { error: rpcError(
|
|
1925
|
+
E.SIG_ROTATION_KEY_MISMATCH,
|
|
1926
|
+
"Rotation must be signed with the old key"
|
|
1927
|
+
) });
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1912
1930
|
}
|
|
1913
1931
|
if (this.options.enforceStepUp && PRIVILEGED_METHODS.has(method)) {
|
|
1914
1932
|
const stale = this.checkStepUp(params);
|
|
@@ -1939,6 +1957,16 @@ var Coordinator = class {
|
|
|
1939
1957
|
}
|
|
1940
1958
|
}
|
|
1941
1959
|
}
|
|
1960
|
+
if (method === "task.create") {
|
|
1961
|
+
const wsId2 = params.workspace;
|
|
1962
|
+
const ws = typeof wsId2 === "string" ? this.workspaces.get(wsId2) : void 0;
|
|
1963
|
+
const key = params.idempotency_key;
|
|
1964
|
+
if (ws && typeof key === "string") {
|
|
1965
|
+
const existingId = ws.idempotency_keys[key];
|
|
1966
|
+
const task = existingId ? ws.tasks.get(existingId) : void 0;
|
|
1967
|
+
if (task) return reply(envelope, { result: { task_id: existingId, state: task.state } });
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1942
1970
|
const handler = this.handlers.get(method);
|
|
1943
1971
|
if (!handler) {
|
|
1944
1972
|
return reply(envelope, { error: rpcError(E.METHOD, `Unknown method: ${method}`) });
|
|
@@ -2052,7 +2080,13 @@ var Coordinator = class {
|
|
|
2052
2080
|
const ws = this.workspaces.get(wsId);
|
|
2053
2081
|
if (!ws) return null;
|
|
2054
2082
|
const member = ws.members.get(sender);
|
|
2055
|
-
if (!member
|
|
2083
|
+
if (!member) return null;
|
|
2084
|
+
if (member.type !== "human" && member.oidc_sub === void 0) return null;
|
|
2085
|
+
if (member.oidc_auth_time === void 0) {
|
|
2086
|
+
return rpcError(E.OIDC_STEP_UP_REQUIRED, "Step-up authentication required", {
|
|
2087
|
+
window_sec: ws.step_up_window_sec
|
|
2088
|
+
});
|
|
2089
|
+
}
|
|
2056
2090
|
const nowSec = Math.floor(Date.now() / 1e3);
|
|
2057
2091
|
const age = nowSec - member.oidc_auth_time;
|
|
2058
2092
|
if (age > ws.step_up_window_sec) {
|
|
@@ -2061,6 +2095,12 @@ var Coordinator = class {
|
|
|
2061
2095
|
age_sec: age
|
|
2062
2096
|
});
|
|
2063
2097
|
}
|
|
2098
|
+
if (ws.min_acr !== void 0 && member.oidc_acr !== ws.min_acr) {
|
|
2099
|
+
return rpcError(E.OIDC_STEP_UP_REQUIRED, "Step-up required: acr below the workspace minimum", {
|
|
2100
|
+
required_acr: ws.min_acr,
|
|
2101
|
+
acr: member.oidc_acr
|
|
2102
|
+
});
|
|
2103
|
+
}
|
|
2064
2104
|
return null;
|
|
2065
2105
|
}
|
|
2066
2106
|
// ==========================================================
|
|
@@ -2110,6 +2150,7 @@ var Coordinator = class {
|
|
|
2110
2150
|
mode_ceiling: p.mode_ceiling ?? "production",
|
|
2111
2151
|
routing_policy_uri: p.routing_policy_uri,
|
|
2112
2152
|
step_up_window_sec: typeof p.step_up_window_sec === "number" ? p.step_up_window_sec : 300,
|
|
2153
|
+
min_acr: p.min_acr,
|
|
2113
2154
|
members: /* @__PURE__ */ new Map(),
|
|
2114
2155
|
tasks: /* @__PURE__ */ new Map(),
|
|
2115
2156
|
overrides: /* @__PURE__ */ new Map(),
|
|
@@ -2118,6 +2159,7 @@ var Coordinator = class {
|
|
|
2118
2159
|
handoffs: /* @__PURE__ */ new Map(),
|
|
2119
2160
|
snapshots: /* @__PURE__ */ new Map(),
|
|
2120
2161
|
route_decisions: /* @__PURE__ */ new Map(),
|
|
2162
|
+
idempotency_keys: {},
|
|
2121
2163
|
audit: [],
|
|
2122
2164
|
chain_enabled: chainEnabled,
|
|
2123
2165
|
chain_head: chainEnabled ? ZERO_HASH : void 0
|
|
@@ -2130,6 +2172,10 @@ var Coordinator = class {
|
|
|
2130
2172
|
if (miss) return { error: rpcError(E.PARAMS, `Missing field: ${miss}`) };
|
|
2131
2173
|
const ws = this.workspaces.get(p.workspace);
|
|
2132
2174
|
if (!ws) return { error: rpcError(E.PARAMS, `Unknown workspace: ${p.workspace}`) };
|
|
2175
|
+
if (this.options.requireReadMembership) {
|
|
2176
|
+
const notMember = this.requireMember(ws, p.from);
|
|
2177
|
+
if (notMember) return notMember;
|
|
2178
|
+
}
|
|
2133
2179
|
return { result: {
|
|
2134
2180
|
id: ws.id,
|
|
2135
2181
|
created: ws.created,
|
|
@@ -2147,10 +2193,15 @@ var Coordinator = class {
|
|
|
2147
2193
|
} };
|
|
2148
2194
|
}
|
|
2149
2195
|
opWorkspaceSetProfiles(p) {
|
|
2150
|
-
const miss = missing(p, ["workspace", "profiles"]);
|
|
2196
|
+
const miss = missing(p, ["workspace", "from", "profiles"]);
|
|
2151
2197
|
if (miss) return { error: rpcError(E.PARAMS, `Missing field: ${miss}`) };
|
|
2152
2198
|
const ws = this.workspaces.get(p.workspace);
|
|
2153
2199
|
if (!ws) return { error: rpcError(E.PARAMS, "Unknown workspace") };
|
|
2200
|
+
const notMember = this.requireMember(ws, p.from);
|
|
2201
|
+
if (notMember) return notMember;
|
|
2202
|
+
if (ws.members.get(p.from).role !== "admin") {
|
|
2203
|
+
return { error: rpcError(E.NOT_AUTHORISED, "workspace.set_profiles requires the admin role") };
|
|
2204
|
+
}
|
|
2154
2205
|
const newProfiles = [...p.profiles];
|
|
2155
2206
|
if (!newProfiles.some((pr) => pr.startsWith("core/"))) newProfiles.push("core/1.0");
|
|
2156
2207
|
ws.profiles = newProfiles;
|
|
@@ -2188,6 +2239,7 @@ var Coordinator = class {
|
|
|
2188
2239
|
member.oidc_sub = claims.sub;
|
|
2189
2240
|
const at = claims.auth_time;
|
|
2190
2241
|
if (typeof at === "number") member.oidc_auth_time = at;
|
|
2242
|
+
member.oidc_acr = claims.acr;
|
|
2191
2243
|
const cnf = claims.cnf;
|
|
2192
2244
|
const cnfJwk = cnf?.jwk;
|
|
2193
2245
|
if (cnfJwk && typeof cnfJwk.kid === "string") {
|
|
@@ -2216,6 +2268,7 @@ var Coordinator = class {
|
|
|
2216
2268
|
if (existing) {
|
|
2217
2269
|
if (member.oidc_sub !== void 0) existing.oidc_sub = member.oidc_sub;
|
|
2218
2270
|
if (member.oidc_auth_time !== void 0) existing.oidc_auth_time = member.oidc_auth_time;
|
|
2271
|
+
if (member.oidc_acr !== void 0) existing.oidc_acr = member.oidc_acr;
|
|
2219
2272
|
if (member.vc_holder !== void 0) existing.vc_holder = member.vc_holder;
|
|
2220
2273
|
for (const k of attested) {
|
|
2221
2274
|
if (!existing.keys.some((x) => x.kid === k.kid)) existing.keys.push(k);
|
|
@@ -2236,6 +2289,8 @@ var Coordinator = class {
|
|
|
2236
2289
|
if (miss) return { error: rpcError(E.PARAMS, `Missing field: ${miss}`) };
|
|
2237
2290
|
const ws = this.workspaces.get(p.workspace);
|
|
2238
2291
|
if (!ws) return { error: rpcError(E.PARAMS, "Unknown workspace") };
|
|
2292
|
+
const notMember = this.requireMember(ws, p.from);
|
|
2293
|
+
if (notMember) return notMember;
|
|
2239
2294
|
const assignee = p.assignee || p.to;
|
|
2240
2295
|
if (!assignee || !ws.members.has(assignee)) {
|
|
2241
2296
|
return { error: rpcError(E.PARAMS, "Assignee not in workspace") };
|
|
@@ -2270,11 +2325,14 @@ var Coordinator = class {
|
|
|
2270
2325
|
if (task.mode === "trial") task.review_required = true;
|
|
2271
2326
|
else if ("review_required" in p) task.review_required = !!p.review_required;
|
|
2272
2327
|
ws.tasks.set(taskId, task);
|
|
2328
|
+
if (typeof p.idempotency_key === "string") ws.idempotency_keys[p.idempotency_key] = taskId;
|
|
2273
2329
|
return { result: { task_id: taskId, state: "created" } };
|
|
2274
2330
|
}
|
|
2275
2331
|
opTaskUpdate(p) {
|
|
2276
2332
|
const ws = this.workspaces.get(p.workspace);
|
|
2277
2333
|
if (!ws) return { error: rpcError(E.PARAMS, "Unknown workspace") };
|
|
2334
|
+
const notMember = this.requireMember(ws, p.from);
|
|
2335
|
+
if (notMember) return notMember;
|
|
2278
2336
|
const task = ws.tasks.get(p.task_id);
|
|
2279
2337
|
if (!task) return { error: rpcError(E.PARAMS, "Unknown task") };
|
|
2280
2338
|
const newState = p.state;
|
|
@@ -2317,6 +2375,10 @@ var Coordinator = class {
|
|
|
2317
2375
|
opAuditRead(p) {
|
|
2318
2376
|
const ws = this.workspaces.get(p.workspace);
|
|
2319
2377
|
if (!ws) return { error: rpcError(E.PARAMS, "Unknown workspace") };
|
|
2378
|
+
if (this.options.requireReadMembership) {
|
|
2379
|
+
const notMember = this.requireMember(ws, p.from);
|
|
2380
|
+
if (notMember) return notMember;
|
|
2381
|
+
}
|
|
2320
2382
|
const range = p.range ?? {};
|
|
2321
2383
|
const filter = p.filter ?? {};
|
|
2322
2384
|
const fromSeq = range.from_seq ?? 0;
|