@ctliz/agent-intercom-pi 0.11.0-connect.2

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.
@@ -0,0 +1,17 @@
1
+ # Third-Party Notices
2
+
3
+ ## pi-intercom
4
+
5
+ Portions of this repository are derived from [Nico Bailon's original
6
+ `pi-intercom`](https://github.com/nicobailon/pi-intercom) and work contributed
7
+ to that project.
8
+
9
+ The original work was made available under the MIT License. Its copyright and
10
+ permission notice are reproduced in [`licenses/MIT-pi-intercom.txt`](licenses/MIT-pi-intercom.txt).
11
+ Those notices must be retained with copies or substantial portions of the
12
+ original MIT-licensed material.
13
+
14
+ The current repository, including later modifications and the combined work,
15
+ is distributed under the GNU Affero General Public License v3.0 or later as
16
+ stated in [`LICENSE`](LICENSE). Previously published MIT-licensed versions
17
+ remain available under the terms under which they were released.
package/banner.png ADDED
Binary file
@@ -0,0 +1,241 @@
1
+ import type { SessionInfo } from "./types.ts";
2
+
3
+ type BossSession = Pick<SessionInfo, "id">;
4
+
5
+ export const BOSS_ENV_NAMES = [
6
+ "AGENT_INTERCOM_BOSS_RUN_ID",
7
+ "AGENT_INTERCOM_BOSS_ROLE",
8
+ "AGENT_INTERCOM_BOSS_CONTROLLER_TARGET",
9
+ "AGENT_INTERCOM_BOSS_MANAGER_TARGET",
10
+ "AGENT_INTERCOM_BOSS_TEAM_TARGETS",
11
+ "AGENT_INTERCOM_BOSS_VISIBILITY",
12
+ ] as const;
13
+
14
+ export type BossRole = "manager" | "worker" | "scout" | "adversary";
15
+ export type BossVisibility = "team-only" | "local";
16
+
17
+ export const ORCHESTRATOR_READINESS_PROBE = "agent-intercom.orchestrator/readiness-probe";
18
+ export const ORCHESTRATOR_READINESS_ACK = "agent-intercom.orchestrator/readiness-ack";
19
+
20
+ export type BossTeamScope =
21
+ | { present: false; restricted: false }
22
+ | {
23
+ present: true;
24
+ restricted: true;
25
+ valid: false;
26
+ error: string;
27
+ }
28
+ | {
29
+ present: true;
30
+ restricted: boolean;
31
+ valid: true;
32
+ runId: string;
33
+ role: BossRole;
34
+ controllerTarget: string;
35
+ managerTarget: string;
36
+ teamTargets: readonly string[];
37
+ selfTarget: string;
38
+ runSuffix: string;
39
+ visibility: BossVisibility;
40
+ };
41
+
42
+ const BOSS_RUN_ID_PATTERN = /^boss-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
43
+ const BOSS_ROLES = ["manager", "worker", "scout", "adversary"] as const;
44
+
45
+ function exactNonEmptyString(value: unknown): value is string {
46
+ return typeof value === "string"
47
+ && value.length > 0
48
+ && value === value.trim()
49
+ && !/[\u0000-\u001f\u007f]/.test(value);
50
+ }
51
+
52
+ function invalid(error: string): BossTeamScope {
53
+ return { present: true, restricted: true, valid: false, error };
54
+ }
55
+
56
+ /**
57
+ * Reads trusted-local Boss metadata. Any Boss key makes the contract active;
58
+ * incomplete or malformed contracts deliberately become a deny-all scope.
59
+ */
60
+ export function readBossTeamScope(env: NodeJS.ProcessEnv = process.env): BossTeamScope {
61
+ if (!BOSS_ENV_NAMES.some((name) => Object.prototype.hasOwnProperty.call(env, name))) {
62
+ return { present: false, restricted: false };
63
+ }
64
+
65
+ const runId = env.AGENT_INTERCOM_BOSS_RUN_ID;
66
+ if (!exactNonEmptyString(runId) || !BOSS_RUN_ID_PATTERN.test(runId)) {
67
+ return invalid("AGENT_INTERCOM_BOSS_RUN_ID must match boss-<lowercase UUID>");
68
+ }
69
+ const runSuffix = runId.slice(-12);
70
+
71
+ const role = env.AGENT_INTERCOM_BOSS_ROLE;
72
+ if (role !== "manager" && role !== "worker" && role !== "scout" && role !== "adversary") {
73
+ return invalid("AGENT_INTERCOM_BOSS_ROLE must be manager, worker, scout, or adversary");
74
+ }
75
+
76
+ const controllerTarget = env.AGENT_INTERCOM_BOSS_CONTROLLER_TARGET;
77
+ if (!exactNonEmptyString(controllerTarget)) {
78
+ return invalid("AGENT_INTERCOM_BOSS_CONTROLLER_TARGET must be a non-empty exact stable session ID");
79
+ }
80
+
81
+ const managerTarget = env.AGENT_INTERCOM_BOSS_MANAGER_TARGET;
82
+ if (!exactNonEmptyString(managerTarget)) {
83
+ return invalid("AGENT_INTERCOM_BOSS_MANAGER_TARGET must be a non-empty exact stable session ID");
84
+ }
85
+ if (managerTarget === controllerTarget) {
86
+ return invalid("Boss Controller and Manager targets must be distinct");
87
+ }
88
+
89
+ const expectedTargets = BOSS_ROLES.map((expectedRole) => `boss-${expectedRole}-${runSuffix}`);
90
+ if (managerTarget !== expectedTargets[0]) {
91
+ return invalid(`AGENT_INTERCOM_BOSS_MANAGER_TARGET must equal ${expectedTargets[0]}`);
92
+ }
93
+
94
+ let teamTargets: unknown;
95
+ try {
96
+ teamTargets = JSON.parse(env.AGENT_INTERCOM_BOSS_TEAM_TARGETS ?? "");
97
+ } catch {
98
+ return invalid("AGENT_INTERCOM_BOSS_TEAM_TARGETS must be a JSON array of exact stable session IDs");
99
+ }
100
+ if (!Array.isArray(teamTargets) || !teamTargets.every(exactNonEmptyString)) {
101
+ return invalid("AGENT_INTERCOM_BOSS_TEAM_TARGETS must be a JSON array of exact stable session IDs");
102
+ }
103
+ const targetSet = new Set(teamTargets);
104
+ if (teamTargets.length !== expectedTargets.length || targetSet.size !== expectedTargets.length || expectedTargets.some((target) => !targetSet.has(target))) {
105
+ return invalid("AGENT_INTERCOM_BOSS_TEAM_TARGETS must contain exactly the canonical manager, worker, scout, and adversary session IDs for the run");
106
+ }
107
+ if (targetSet.has(controllerTarget)) {
108
+ return invalid("AGENT_INTERCOM_BOSS_CONTROLLER_TARGET must be distinct from every canonical team target");
109
+ }
110
+
111
+ const visibility = env.AGENT_INTERCOM_BOSS_VISIBILITY ?? "team-only";
112
+ if (visibility !== "team-only" && visibility !== "local") {
113
+ return invalid("AGENT_INTERCOM_BOSS_VISIBILITY must be team-only or local");
114
+ }
115
+
116
+ return {
117
+ present: true,
118
+ restricted: visibility === "team-only",
119
+ valid: true,
120
+ runId,
121
+ role,
122
+ controllerTarget,
123
+ managerTarget,
124
+ teamTargets: Object.freeze(expectedTargets),
125
+ selfTarget: `boss-${role}-${runSuffix}`,
126
+ runSuffix,
127
+ visibility,
128
+ };
129
+ }
130
+
131
+ export function bossSelfSessionError(scope: BossTeamScope, selfId: string): string | undefined {
132
+ if (!scope.present || !scope.valid) return scope.present && "error" in scope ? scope.error : undefined;
133
+ return selfId === scope.selfTarget
134
+ ? undefined
135
+ : `Boss session identity mismatch: expected ${scope.selfTarget}, received ${selfId}`;
136
+ }
137
+
138
+ /** Exact stable session IDs this Boss role may address in team-only mode. */
139
+ export function bossAllowedTargets(scope: BossTeamScope): ReadonlySet<string> | undefined {
140
+ if (!scope.restricted) return undefined;
141
+ if (!scope.valid) return new Set();
142
+
143
+ const allowed = new Set(scope.teamTargets);
144
+ if (scope.role === "manager") allowed.add(scope.controllerTarget);
145
+ else allowed.delete(scope.controllerTarget);
146
+ return allowed;
147
+ }
148
+
149
+ function liveAllowedIds<T extends BossSession>(scope: BossTeamScope, sessions: readonly T[]): Set<string> {
150
+ const liveIds = new Set(sessions.map((session) => session.id));
151
+ return new Set([...bossAllowedTargets(scope) ?? []].filter((target) => liveIds.has(target)));
152
+ }
153
+
154
+ export type BossTargetResolution =
155
+ | { allowed: true; targetId: string }
156
+ | {
157
+ allowed: false;
158
+ code: "BOSS_TEAM_METADATA_INVALID" | "BOSS_TEAM_SCOPE_DENIED" | "BOSS_TEAM_TARGET_NOT_CONNECTED";
159
+ error: string;
160
+ };
161
+
162
+ export class BossTeamScopeError extends Error {
163
+ constructor(
164
+ readonly code: Exclude<BossTargetResolution, { allowed: true }>["code"],
165
+ message: string,
166
+ ) {
167
+ super(message);
168
+ this.name = "BossTeamScopeError";
169
+ }
170
+ }
171
+
172
+ /** Resolves only an exact live stable session ID; names and ID prefixes are denied. */
173
+ export function resolveBossLiveTarget<T extends BossSession>(
174
+ scope: BossTeamScope,
175
+ target: string,
176
+ sessions: readonly T[],
177
+ selfId?: string,
178
+ ): BossTargetResolution {
179
+ if (!scope.present) return { allowed: true, targetId: target };
180
+ if (!scope.valid) {
181
+ return { allowed: false, code: "BOSS_TEAM_METADATA_INVALID", error: `Boss team scope is unavailable: ${"error" in scope ? scope.error : "invalid metadata"}` };
182
+ }
183
+ if (selfId !== undefined) {
184
+ const selfError = bossSelfSessionError(scope, selfId);
185
+ if (selfError) return { allowed: false, code: "BOSS_TEAM_METADATA_INVALID", error: selfError };
186
+ }
187
+
188
+ if (scope.restricted && !bossAllowedTargets(scope)!.has(target)) {
189
+ return { allowed: false, code: "BOSS_TEAM_SCOPE_DENIED", error: `Boss team scope denied exact session ID "${target}"; use an exact ID returned by intercom_team` };
190
+ }
191
+ if (!sessions.some((session) => session.id === target)) {
192
+ return { allowed: false, code: "BOSS_TEAM_TARGET_NOT_CONNECTED", error: `Boss target exact session ID "${target}" is not connected` };
193
+ }
194
+ return { allowed: true, targetId: target };
195
+ }
196
+
197
+ export function isBossControllerReadinessControl(
198
+ scope: BossTeamScope,
199
+ direction: "inbound" | "outbound",
200
+ peerId: string,
201
+ selfId: string,
202
+ control: { type: string; version: number } | undefined,
203
+ ): boolean {
204
+ if (!scope.present || !scope.valid || !scope.restricted) return false;
205
+ if (bossSelfSessionError(scope, selfId)) return false;
206
+ if (scope.role === "manager" || peerId !== scope.controllerTarget || control?.version !== 1) return false;
207
+ return control.type === (direction === "inbound" ? ORCHESTRATOR_READINESS_PROBE : ORCHESTRATOR_READINESS_ACK);
208
+ }
209
+
210
+ /** Authorizes an inbound sender before any inbox or reply state is mutated. */
211
+ export function authorizeBossSender(scope: BossTeamScope, senderId: string, selfId: string): BossTargetResolution {
212
+ if (!scope.present) return { allowed: true, targetId: senderId };
213
+ if (!scope.valid) {
214
+ return { allowed: false, code: "BOSS_TEAM_METADATA_INVALID", error: `Boss team scope is unavailable: ${"error" in scope ? scope.error : "invalid metadata"}` };
215
+ }
216
+ const selfError = bossSelfSessionError(scope, selfId);
217
+ if (selfError) return { allowed: false, code: "BOSS_TEAM_METADATA_INVALID", error: selfError };
218
+ if (scope.restricted && !bossAllowedTargets(scope)!.has(senderId)) {
219
+ return { allowed: false, code: "BOSS_TEAM_SCOPE_DENIED", error: `Boss team scope denied inbound exact session ID "${senderId}" for role=${scope.role}` };
220
+ }
221
+ return { allowed: true, targetId: senderId };
222
+ }
223
+
224
+ /** Returns the session with this exact stable ID. */
225
+ export function resolveBossLiveSession<T extends BossSession>(sessions: readonly T[], target: string): T | undefined {
226
+ return sessions.find((session) => session.id === target);
227
+ }
228
+
229
+ /** Keeps self plus live exact-ID sessions allowed by the Boss visibility policy. */
230
+ export function filterBossSessions<T extends Pick<SessionInfo, "id">>(
231
+ scope: BossTeamScope,
232
+ sessions: readonly T[],
233
+ selfId: string,
234
+ ): T[] {
235
+ if (!scope.present) return [...sessions];
236
+ if (bossSelfSessionError(scope, selfId)) return sessions.filter((session) => session.id === selfId);
237
+ const allowed = bossAllowedTargets(scope);
238
+ if (!allowed) return [...sessions];
239
+ const allowedIds = liveAllowedIds(scope, sessions);
240
+ return sessions.filter((session) => session.id === selfId || allowedIds.has(session.id));
241
+ }
@@ -0,0 +1,76 @@
1
+ import { readFileSync } from "fs";
2
+ import { writeDurableJson } from "../durable-json.ts";
3
+ import type { RemoteAccessMetadata, RemoteRegistrationAccess } from "../types.ts";
4
+
5
+ export const ACCESS_CREDENTIAL_ENV = "AGENT_INTERCOM_ACCESS_CREDENTIAL_PATH";
6
+ export const ACCESS_CREDENTIAL_VERSION = 1;
7
+
8
+ export interface EnrollmentCredentialFile {
9
+ version?: typeof ACCESS_CREDENTIAL_VERSION;
10
+ enrollmentToken: string;
11
+ }
12
+
13
+ export interface SessionCredentialFile {
14
+ version: typeof ACCESS_CREDENTIAL_VERSION;
15
+ sessionCredential: string;
16
+ sessionId: string;
17
+ generation: number;
18
+ }
19
+
20
+ export interface LoadedRemoteAccessCredential {
21
+ path: string;
22
+ access: RemoteRegistrationAccess;
23
+ enrollment: boolean;
24
+ }
25
+
26
+ function nonEmptyString(value: unknown): value is string {
27
+ return typeof value === "string" && value.length > 0 && !value.includes("\0");
28
+ }
29
+
30
+ export function loadRemoteAccessCredential(env: NodeJS.ProcessEnv = process.env): LoadedRemoteAccessCredential | undefined {
31
+ const path = env[ACCESS_CREDENTIAL_ENV]?.trim();
32
+ if (!path) return undefined;
33
+ const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
34
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
35
+ throw new Error(`Invalid Agent Intercom access credential at ${path}`);
36
+ }
37
+ const credential = parsed as Record<string, unknown>;
38
+ if (nonEmptyString(credential.enrollmentToken)) {
39
+ return { path, access: { enrollmentToken: credential.enrollmentToken }, enrollment: true };
40
+ }
41
+ if (
42
+ credential.version === ACCESS_CREDENTIAL_VERSION
43
+ && nonEmptyString(credential.sessionCredential)
44
+ && nonEmptyString(credential.sessionId)
45
+ && typeof credential.generation === "number"
46
+ && Number.isSafeInteger(credential.generation)
47
+ && credential.generation > 0
48
+ ) {
49
+ return {
50
+ path,
51
+ access: {
52
+ sessionCredential: credential.sessionCredential,
53
+ sessionId: credential.sessionId,
54
+ generation: credential.generation,
55
+ },
56
+ enrollment: false,
57
+ };
58
+ }
59
+ throw new Error(`Invalid Agent Intercom access credential at ${path}`);
60
+ }
61
+
62
+ export function writeRemoteSessionCredential(
63
+ path: string,
64
+ sessionId: string,
65
+ metadata: RemoteAccessMetadata,
66
+ ): void {
67
+ if (!metadata.sessionCredential) {
68
+ throw new Error("Remote enrollment response omitted the session credential");
69
+ }
70
+ writeDurableJson(path, {
71
+ version: ACCESS_CREDENTIAL_VERSION,
72
+ sessionCredential: metadata.sessionCredential,
73
+ sessionId,
74
+ generation: metadata.generation,
75
+ } satisfies SessionCredentialFile);
76
+ }