agent-relay-server 0.122.0 → 0.123.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/docs/openapi.json +1 -1
- package/package.json +7 -8
- package/public/assets/{MessageBubble-DRdUD-kW.js → MessageBubble-BTeFExjj.js} +2 -2
- package/public/assets/{MessageBubble-DRdUD-kW.js.map → MessageBubble-BTeFExjj.js.map} +1 -1
- package/public/assets/{PlanGraphPanel-siKMPCln.js → PlanGraphPanel-jU1DXg7w.js} +2 -2
- package/public/assets/{PlanGraphPanel-siKMPCln.js.map → PlanGraphPanel-jU1DXg7w.js.map} +1 -1
- package/public/assets/{activity-D3MNcSaV.js → activity-DUig2iYW.js} +2 -2
- package/public/assets/{activity-D3MNcSaV.js.map → activity-DUig2iYW.js.map} +1 -1
- package/public/assets/{agent-profiles-CKzttq6G.js → agent-profiles-D-oFmb6S.js} +2 -2
- package/public/assets/{agent-profiles-CKzttq6G.js.map → agent-profiles-D-oFmb6S.js.map} +1 -1
- package/public/assets/{agent-type-icon-0ZJRP1Vy.js → agent-type-icon-Dan2l3Tm.js} +2 -2
- package/public/assets/{agent-type-icon-0ZJRP1Vy.js.map → agent-type-icon-Dan2l3Tm.js.map} +1 -1
- package/public/assets/{agents-CuVj_rfG.js → agents-BkC6mcTh.js} +2 -2
- package/public/assets/{agents-CuVj_rfG.js.map → agents-BkC6mcTh.js.map} +1 -1
- package/public/assets/{analytics-iob6C27d.js → analytics-C3Dlmqe9.js} +2 -2
- package/public/assets/{analytics-iob6C27d.js.map → analytics-C3Dlmqe9.js.map} +1 -1
- package/public/assets/{automation-B2ixxs4q.js → automation-AeMZ70WQ.js} +2 -2
- package/public/assets/{automation-B2ixxs4q.js.map → automation-AeMZ70WQ.js.map} +1 -1
- package/public/assets/{branch-state-badge-CafBJWKo.js → branch-state-badge-CNW10MTC.js} +2 -2
- package/public/assets/{branch-state-badge-CafBJWKo.js.map → branch-state-badge-CNW10MTC.js.map} +1 -1
- package/public/assets/{channels-C-WsbL2H.js → channels-Bc_mEd56.js} +2 -2
- package/public/assets/{channels-C-WsbL2H.js.map → channels-Bc_mEd56.js.map} +1 -1
- package/public/assets/{chat-DeoVTVob.js → chat-BCNCuTgw.js} +2 -2
- package/public/assets/{chat-DeoVTVob.js.map → chat-BCNCuTgw.js.map} +1 -1
- package/public/assets/{connectors-C2Ac03LJ.js → connectors-h0d5Mc6e.js} +2 -2
- package/public/assets/{connectors-C2Ac03LJ.js.map → connectors-h0d5Mc6e.js.map} +1 -1
- package/public/assets/{display-CJzSoTMq.js → display-GFbGUG0O.js} +2 -2
- package/public/assets/{display-CJzSoTMq.js.map → display-GFbGUG0O.js.map} +1 -1
- package/public/assets/{formatted-body-35XBOY5L.js → formatted-body-CVr3Iev9.js} +3 -3
- package/public/assets/{formatted-body-35XBOY5L.js.map → formatted-body-CVr3Iev9.js.map} +1 -1
- package/public/assets/{formatted-body-impl-RmDxI5Ux.js → formatted-body-impl-Cq5SRGpm.js} +2 -2
- package/public/assets/{formatted-body-impl-RmDxI5Ux.js.map → formatted-body-impl-Cq5SRGpm.js.map} +1 -1
- package/public/assets/{index-D0xMQQb_.js → index--9UMzCFf.js} +6 -6
- package/public/assets/{index-D0xMQQb_.js.map → index--9UMzCFf.js.map} +1 -1
- package/public/assets/{insights-B643SFvm.js → insights-C8lIBXg3.js} +2 -2
- package/public/assets/{insights-B643SFvm.js.map → insights-C8lIBXg3.js.map} +1 -1
- package/public/assets/{integrations-hFIHeCF4.js → integrations-7OFsJtY7.js} +2 -2
- package/public/assets/{integrations-hFIHeCF4.js.map → integrations-7OFsJtY7.js.map} +1 -1
- package/public/assets/{maintenance-CURvdp_Z.js → maintenance-HDpg20OY.js} +2 -2
- package/public/assets/{maintenance-CURvdp_Z.js.map → maintenance-HDpg20OY.js.map} +1 -1
- package/public/assets/{managed-agents-DrZtdlSn.js → managed-agents-muCIMxng.js} +2 -2
- package/public/assets/{managed-agents-DrZtdlSn.js.map → managed-agents-muCIMxng.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-CVDO--ek.js → markdown-preview-impl-Cx7pCfA6.js} +2 -2
- package/public/assets/{markdown-preview-impl-CVDO--ek.js.map → markdown-preview-impl-Cx7pCfA6.js.map} +1 -1
- package/public/assets/{memory-Bm7dt_Qf.js → memory-CTO1FfJ-.js} +2 -2
- package/public/assets/{memory-Bm7dt_Qf.js.map → memory-CTO1FfJ-.js.map} +1 -1
- package/public/assets/{messages-DTq4i2KZ.js → messages-RWSXG2UM.js} +2 -2
- package/public/assets/{messages-DTq4i2KZ.js.map → messages-RWSXG2UM.js.map} +1 -1
- package/public/assets/{orchestrators-Dra318Ap.js → orchestrators-5aiYw3yx.js} +2 -2
- package/public/assets/{orchestrators-Dra318Ap.js.map → orchestrators-5aiYw3yx.js.map} +1 -1
- package/public/assets/{overview-yr1Vmk64.js → overview-Du6XLt5l.js} +2 -2
- package/public/assets/{overview-yr1Vmk64.js.map → overview-Du6XLt5l.js.map} +1 -1
- package/public/assets/{pairs-mnlKDBGp.js → pairs-BDRnlEta.js} +2 -2
- package/public/assets/{pairs-mnlKDBGp.js.map → pairs-BDRnlEta.js.map} +1 -1
- package/public/assets/{projects-Dzdf-gkK.js → projects-DwsWE9es.js} +2 -2
- package/public/assets/{projects-Dzdf-gkK.js.map → projects-DwsWE9es.js.map} +1 -1
- package/public/assets/{prompt-settings-ByL8SNCi.js → prompt-settings-CaJX_LbA.js} +2 -2
- package/public/assets/{prompt-settings-ByL8SNCi.js.map → prompt-settings-CaJX_LbA.js.map} +1 -1
- package/public/assets/{registry-CXWyOtpr.js → registry-C-uIL0Nl.js} +2 -2
- package/public/assets/{registry-CXWyOtpr.js.map → registry-C-uIL0Nl.js.map} +1 -1
- package/public/assets/{security-0SBsc_4W.js → security-BpVrdYhJ.js} +2 -2
- package/public/assets/{security-0SBsc_4W.js.map → security-BpVrdYhJ.js.map} +1 -1
- package/public/assets/{select-Bw5z2KJ_.js → select-DallbU93.js} +2 -2
- package/public/assets/{select-Bw5z2KJ_.js.map → select-DallbU93.js.map} +1 -1
- package/public/assets/{settings-78Cyq_tA.js → settings-BUQirdyI.js} +2 -2
- package/public/assets/{settings-78Cyq_tA.js.map → settings-BUQirdyI.js.map} +1 -1
- package/public/assets/{store-BPrVuKiv.js → store-DMZSTozC.js} +2 -2
- package/public/assets/{store-BPrVuKiv.js.map → store-DMZSTozC.js.map} +1 -1
- package/public/assets/{tasks-Cg2MMeri.js → tasks-k8mQDfKy.js} +2 -2
- package/public/assets/{tasks-Cg2MMeri.js.map → tasks-k8mQDfKy.js.map} +1 -1
- package/public/assets/{teams-DWv6UwFV.js → teams-DI-Lhhbl.js} +2 -2
- package/public/assets/{teams-DWv6UwFV.js.map → teams-DI-Lhhbl.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-DBLDjbIg.js → terminal-viewer-impl-BL853Fpi.js} +2 -2
- package/public/assets/{terminal-viewer-impl-DBLDjbIg.js.map → terminal-viewer-impl-BL853Fpi.js.map} +1 -1
- package/public/assets/types-CRptbSYh.js +2 -0
- package/public/assets/types-CRptbSYh.js.map +1 -0
- package/public/assets/{user-avatar-BsOLyVJj.js → user-avatar-D9xyGi3u.js} +2 -2
- package/public/assets/{user-avatar-BsOLyVJj.js.map → user-avatar-D9xyGi3u.js.map} +1 -1
- package/public/assets/{work-queue-DmwvnF6F.js → work-queue-DrLIdvxB.js} +2 -2
- package/public/assets/{work-queue-DmwvnF6F.js.map → work-queue-DrLIdvxB.js.map} +1 -1
- package/public/assets/{workspaces-dIBivJN8.js → workspaces-CnNL6T8Q.js} +2 -2
- package/public/assets/{workspaces-dIBivJN8.js.map → workspaces-CnNL6T8Q.js.map} +1 -1
- package/public/index.html +6 -6
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/src/adapters/claude-delivery.ts +127 -0
- package/runner/src/adapters/claude-quota-harvest.ts +92 -0
- package/runner/src/adapters/claude-session-probe.ts +225 -0
- package/runner/src/adapters/claude-status-detectors.ts +147 -0
- package/runner/src/adapters/claude-transcript-tail.ts +128 -0
- package/runner/src/adapters/claude-transcript.ts +414 -0
- package/runner/src/adapters/claude.ts +675 -0
- package/runner/src/adapters/codex-agent-message-capture.ts +139 -0
- package/runner/src/adapters/codex-client.ts +279 -0
- package/runner/src/adapters/codex.ts +1345 -0
- package/runner/src/attachment-cache.ts +189 -0
- package/runner/src/busy-reconciler.ts +102 -0
- package/runner/src/claim-tracker.ts +140 -0
- package/runner/src/claude-prompt-gates.ts +268 -0
- package/runner/src/codex-version.ts +63 -0
- package/runner/src/config.ts +7 -0
- package/runner/src/context-probe-state.ts +6 -0
- package/runner/src/continuation-archive.ts +179 -0
- package/runner/src/control-server.ts +639 -0
- package/runner/src/index.ts +396 -0
- package/runner/src/launch-assembly.ts +674 -0
- package/runner/src/liveness.ts +50 -0
- package/runner/src/logger.ts +99 -0
- package/runner/src/mcp-outbox.ts +120 -0
- package/runner/src/message-body-config/config.ts +3 -0
- package/runner/src/message-body-config.ts +1 -0
- package/runner/src/native-self-resume.ts +202 -0
- package/runner/src/outbox.ts +342 -0
- package/runner/src/process-meta.ts +9 -0
- package/runner/src/profile-home.ts +260 -0
- package/runner/src/profile-projection.ts +324 -0
- package/runner/src/providers.ts +20 -0
- package/runner/src/provisioning.ts +368 -0
- package/runner/src/quota.ts +40 -0
- package/runner/src/rate-limit.ts +189 -0
- package/runner/src/relay-injection-events.ts +105 -0
- package/runner/src/relay-instructions.ts +60 -0
- package/runner/src/relay-mcp-proxy.ts +383 -0
- package/runner/src/relay-mcp.ts +156 -0
- package/runner/src/reply-obligation-cache.ts +136 -0
- package/runner/src/response-capture-report.ts +63 -0
- package/runner/src/runner-core.ts +2409 -0
- package/runner/src/runner-helpers.ts +435 -0
- package/runner/src/runner-insights.ts +105 -0
- package/runner/src/runner.ts +14 -0
- package/runner/src/session-destroy.ts +22 -0
- package/runner/src/session-insights.ts +118 -0
- package/runner/src/session-scratch.ts +271 -0
- package/runner/src/template-resolver.ts +29 -0
- package/runner/src/version.ts +44 -0
- package/src/config-store.ts +2 -0
- package/src/db/provisioning-registry.ts +40 -9
- package/src/db/provisioning-resolve.ts +66 -5
- package/src/gate-resolver.ts +7 -12
- package/src/routes/provisioning-registry.ts +1 -1
- package/src/services/spawn-agent.ts +1 -0
- package/public/assets/types-BeJUSfDj.js +0 -2
- package/public/assets/types-BeJUSfDj.js.map +0 -1
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import type { AgentProfile, AgentProfileProjectionEntry, AgentProfileProjectionReport, SpawnProvider } from "agent-relay-sdk";
|
|
2
|
+
import { getManifest } from "agent-relay-providers";
|
|
3
|
+
import type { AssembledLaunch } from "./launch-assembly";
|
|
4
|
+
|
|
5
|
+
// #557 — the projection report DESCRIBES an AssembledLaunch, the same object the adapters
|
|
6
|
+
// turn into launch args. It is no longer a separate re-derivation from the profile, so the
|
|
7
|
+
// report and the real launch share one source of truth and cannot drift: change the
|
|
8
|
+
// assembler and both the args AND this report change together. Every entry below reads a
|
|
9
|
+
// field the assembler actually computed (relay gates, provisioned sets, instruction
|
|
10
|
+
// disposition, vanilla mechanism, config home) — only the not-yet-enforced category modes
|
|
11
|
+
// (mcp/hooks) and the purely-declarative env/permissions read straight off the profile.
|
|
12
|
+
|
|
13
|
+
interface AgentProfileProjectionInput {
|
|
14
|
+
assembled: AssembledLaunch;
|
|
15
|
+
generatedAt?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function agentProfileProjectionReport(input: AgentProfileProjectionInput): AgentProfileProjectionReport {
|
|
19
|
+
const { assembled } = input;
|
|
20
|
+
const { provider } = assembled;
|
|
21
|
+
const profile = assembled.profile;
|
|
22
|
+
const generatedAt = input.generatedAt ?? Date.now();
|
|
23
|
+
const entries: AgentProfileProjectionEntry[] = [];
|
|
24
|
+
const add = (entry: AgentProfileProjectionEntry) => entries.push(entry);
|
|
25
|
+
|
|
26
|
+
add(relayContextEntry(assembled));
|
|
27
|
+
add(relaySkillsEntry(assembled));
|
|
28
|
+
add(relayPluginsEntry(assembled));
|
|
29
|
+
add(relayStatusLineEntry(assembled));
|
|
30
|
+
add(repoInstructionsEntry(assembled));
|
|
31
|
+
add(globalInstructionsEntry(assembled));
|
|
32
|
+
add(mcpEntry(assembled));
|
|
33
|
+
add(hooksEntry(assembled));
|
|
34
|
+
add(provisioningSkillsEntry(assembled));
|
|
35
|
+
add(provisioningPluginsEntry(assembled));
|
|
36
|
+
add(provisioningHooksEntry(assembled));
|
|
37
|
+
add(hostSkillsEntry(assembled));
|
|
38
|
+
add(hostPluginsEntry(assembled));
|
|
39
|
+
add(provisioningMcpEntry(assembled));
|
|
40
|
+
for (const entry of provisioningSkippedEntries(assembled)) add(entry);
|
|
41
|
+
add(projectMcpEntry(assembled));
|
|
42
|
+
add(projectSkillsEntry(assembled));
|
|
43
|
+
add(projectSettingsEntry(assembled));
|
|
44
|
+
add(sharedMcpEntry(assembled));
|
|
45
|
+
if (profile) add(filesystemEntry(profile));
|
|
46
|
+
add(configHomeEntry(assembled));
|
|
47
|
+
if (assembled.vanilla) add(vanillaLaunchEntry(provider));
|
|
48
|
+
if (profile) add(envEntry(profile));
|
|
49
|
+
|
|
50
|
+
const warnings = entries
|
|
51
|
+
.filter((entry) => entry.result === "partial" || entry.result === "unsupported")
|
|
52
|
+
.map((entry) => `${entry.capability}: ${entry.detail}`);
|
|
53
|
+
const unsupported = entries
|
|
54
|
+
.filter((entry) => entry.result === "unsupported")
|
|
55
|
+
.map((entry) => entry.capability);
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
profileName: profile?.name ?? "default",
|
|
59
|
+
provider,
|
|
60
|
+
base: assembled.base,
|
|
61
|
+
generatedAt,
|
|
62
|
+
entries,
|
|
63
|
+
warnings,
|
|
64
|
+
unsupported,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function relayContextEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
69
|
+
return a.relayContext
|
|
70
|
+
? applied("relay.context", "enabled", "Relay context is injected before Relay-delivered provider turns.")
|
|
71
|
+
: applied("relay.context", "disabled", "Relay context injection is disabled by the profile.");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function relaySkillsEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
75
|
+
const manifest = getManifest(a.provider);
|
|
76
|
+
const label = manifest?.label ?? a.provider;
|
|
77
|
+
const hasPluginSurface = Boolean(manifest?.provisioning?.bundledPlugin);
|
|
78
|
+
if (!hasPluginSurface) {
|
|
79
|
+
return a.relaySkills
|
|
80
|
+
? applied("relay.skills", "enabled", `Bundled Agent Relay ${label} skills are passed through the provider's skill delivery mechanism.`)
|
|
81
|
+
: applied("relay.skills", "disabled", `Bundled Agent Relay ${label} skills are omitted.`);
|
|
82
|
+
}
|
|
83
|
+
return a.relaySkills
|
|
84
|
+
? applied("relay.skills", "enabled", `Agent Relay ${label} skills are available through the bundled Relay plugin.`)
|
|
85
|
+
: applied("relay.skills", "disabled", a.relayPlugin
|
|
86
|
+
? `${label} does not expose an independent Relay skill switch; disabling skills requires disabling the Relay plugin.`
|
|
87
|
+
: `Bundled Agent Relay ${label} plugin dirs are omitted, so Relay plugin-provided skills are unavailable.`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function relayPluginsEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
91
|
+
const manifest = getManifest(a.provider);
|
|
92
|
+
const label = manifest?.label ?? a.provider;
|
|
93
|
+
const hasPluginSurface = Boolean(manifest?.provisioning?.bundledPlugin);
|
|
94
|
+
if (hasPluginSurface) {
|
|
95
|
+
return a.relayPlugin
|
|
96
|
+
? applied("relay.plugins", "enabled", `Bundled Agent Relay ${label} plugin dir is passed to ${label}.`)
|
|
97
|
+
: applied("relay.plugins", "disabled", `Bundled Agent Relay ${label} plugin dirs are omitted.`);
|
|
98
|
+
}
|
|
99
|
+
return notApplicable("relay.plugins", a.relaySkills ? "enabled" : "disabled", `${label} Relay integration uses skills/app-server delivery, not a Relay plugin dir.`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function relayStatusLineEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
103
|
+
const manifest = getManifest(a.provider);
|
|
104
|
+
const label = manifest?.label ?? a.provider;
|
|
105
|
+
if (a.statusLine) {
|
|
106
|
+
return applied("relay.statusLine", "enabled", "Agent Relay status-line context probe settings are injected when caller settings allow it.");
|
|
107
|
+
}
|
|
108
|
+
const hasPluginSurface = Boolean(manifest?.provisioning?.bundledPlugin);
|
|
109
|
+
if (hasPluginSurface) {
|
|
110
|
+
return applied("relay.statusLine", "disabled", "Agent Relay status-line settings are omitted.");
|
|
111
|
+
}
|
|
112
|
+
return notApplicable("relay.statusLine", "disabled", `${label} reports context through provider-native events instead of a Relay status-line setting.`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function repoInstructionsEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
116
|
+
const disposition = a.instructions.repo;
|
|
117
|
+
if (disposition === "allow") return applied("instructions.repo", "allow", "Repo-local provider instructions are left available.");
|
|
118
|
+
if (disposition === "suppressed") {
|
|
119
|
+
const label = getManifest(a.provider)?.label ?? a.provider;
|
|
120
|
+
return applied("instructions.repo", "ignore", `Repo project instructions are suppressed: ${label} launches with the vanilla base mechanism (provider-specific suppression of repo instructions).`);
|
|
121
|
+
}
|
|
122
|
+
return unsupported("instructions.repo", "ignore", "Repo instruction suppression requires the vanilla base; isolated/minimal do not enforce it at launch yet.");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// #552/#554/#555/#556 — the vanilla base's launch-time host suppression, naming the exact
|
|
126
|
+
// provider mechanism the assembler emitted (Claude --setting-sources "user"; Codex
|
|
127
|
+
// project_doc_max_bytes=0). OS-level admin/managed policy is beyond any client flag and is
|
|
128
|
+
// called out so it isn't mistaken for a leak.
|
|
129
|
+
const VANILLA_MECHANISM: Record<string, { requested: string; detail: string }> = {
|
|
130
|
+
claude: {
|
|
131
|
+
requested: "--setting-sources user",
|
|
132
|
+
detail: "Claude launches the isolated config home under --setting-sources \"user\": host CLAUDE.md (repo + global), host skills/plugins/hooks, and host MCP (.mcp.json / ~/.claude.json) are all excluded; relay-provisioned assets in the home load. Auth, model, and built-in tools work normally. OS-level admin-managed policy still applies.",
|
|
133
|
+
},
|
|
134
|
+
codex: {
|
|
135
|
+
requested: "project_doc_max_bytes=0",
|
|
136
|
+
detail: "Codex launches with an isolated CODEX_HOME (no host config.toml MCP/hooks) and project_doc_max_bytes=0 (no AGENTS.md project doc, repo or global).",
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
function vanillaLaunchEntry(provider: SpawnProvider): AgentProfileProjectionEntry {
|
|
141
|
+
const label = getManifest(provider)?.label ?? provider;
|
|
142
|
+
const mechanism = VANILLA_MECHANISM[provider];
|
|
143
|
+
return applied(
|
|
144
|
+
"provider.vanilla",
|
|
145
|
+
mechanism?.requested ?? "active",
|
|
146
|
+
mechanism?.detail ?? `${label} launches with the vanilla base: an isolated provider config home and provider-specific repo instruction suppression. Auth, model, and built-in tools work normally.`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function provisioningSkillsEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
151
|
+
const count = a.skills.length;
|
|
152
|
+
if (!count) return notApplicable("provisioning.skills", "none", "No relay-provisioned skills materialized for this launch.");
|
|
153
|
+
const names = ` (${a.skills.map((s) => s.name).join(", ")})`;
|
|
154
|
+
const label = getManifest(a.provider)?.label ?? a.provider;
|
|
155
|
+
return applied("provisioning.skills", `${count}`, `Relay-provisioned skills materialized for ${label} from the isolated provider config home${names}.`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function provisioningPluginsEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
159
|
+
const manifest = getManifest(a.provider);
|
|
160
|
+
const label = manifest?.label ?? a.provider;
|
|
161
|
+
const hasPluginSurface = Boolean(manifest?.provisioning?.bundledPlugin);
|
|
162
|
+
if (!hasPluginSurface) {
|
|
163
|
+
const declared = (a.profile?.plugins ?? []).filter((p) => p.enabled).length;
|
|
164
|
+
return notApplicable("provisioning.plugins", `${declared}`, `${label} has no plugin surface; provisioned plugins apply to plugin-capable providers only.`);
|
|
165
|
+
}
|
|
166
|
+
const count = a.plugins.length;
|
|
167
|
+
if (!count) return notApplicable("provisioning.plugins", "none", "No relay-provisioned plugins materialized for this launch.");
|
|
168
|
+
const names = ` (${a.plugins.map((p) => p.name).join(", ")})`;
|
|
169
|
+
return applied("provisioning.plugins", `${count}`, `Relay-provisioned plugins passed to ${label} via the plugin dir mechanism${names}.`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function provisioningHooksEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
173
|
+
// #1096 review — the anti-lie invariant: hooks that RESOLVED but did NOT reach the launch
|
|
174
|
+
// (baseline safety guard included) are reported LOUDLY as a warning, never "applied" and never
|
|
175
|
+
// a benign "not-applicable". `hooksSuppressed` is set only when there were hooks to deliver.
|
|
176
|
+
if (a.hooksSuppressed?.names.length) {
|
|
177
|
+
return partial(
|
|
178
|
+
"provisioning.hooks",
|
|
179
|
+
"suppressed",
|
|
180
|
+
`Relay-provisioned hooks were NOT applied (${a.hooksSuppressed.names.join(", ")}): ${a.hooksSuppressed.reason}. A baseline safety guard is absent for this launch.`,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
const count = a.hooks.length;
|
|
184
|
+
if (!count) return notApplicable("provisioning.hooks", "none", "No relay-provisioned hooks materialized for this launch.");
|
|
185
|
+
const names = ` (${a.hooks.map((h) => h.name).join(", ")})`;
|
|
186
|
+
const label = getManifest(a.provider)?.label ?? a.provider;
|
|
187
|
+
return applied("provisioning.hooks", `${count}`, `Relay-provisioned hooks materialized for ${label} from the managed provider config home${names}.`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function hostSkillsEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
191
|
+
const optedIn = Boolean(a.profile?.hostAssets?.skills);
|
|
192
|
+
if (!optedIn) return notApplicable("hostAssets.skills", "off", "Host/global skill inheritance is off for this resolved profile.");
|
|
193
|
+
const label = getManifest(a.provider)?.label ?? a.provider;
|
|
194
|
+
if (!getManifest(a.provider)?.provisioning?.bundledPlugin) {
|
|
195
|
+
return notApplicable("hostAssets.skills", "unsupported", `${label} does not expose host skill-dir projection through Agent Relay.`);
|
|
196
|
+
}
|
|
197
|
+
if (!a.hostSkills.length) return applied("hostAssets.skills", "none", "Host/global skill inheritance is on, but no valid host skill dirs were found.");
|
|
198
|
+
const names = a.hostSkills.map((s) => s.name).join(", ");
|
|
199
|
+
return applied("hostAssets.skills", `${a.hostSkills.length}`, `Host/global skills materialized into Relay's managed ${label} config home (${names}).`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function hostPluginsEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
203
|
+
const optedIn = Boolean(a.profile?.hostAssets?.plugins);
|
|
204
|
+
if (!optedIn) return notApplicable("hostAssets.plugins", "off", "Host/global plugin inheritance is off for this resolved profile.");
|
|
205
|
+
const label = getManifest(a.provider)?.label ?? a.provider;
|
|
206
|
+
if (!getManifest(a.provider)?.provisioning?.bundledPlugin) {
|
|
207
|
+
return notApplicable("hostAssets.plugins", "unsupported", `${label} has no plugin-dir surface for host plugin inheritance.`);
|
|
208
|
+
}
|
|
209
|
+
if (!a.hostPluginDirs.length) return applied("hostAssets.plugins", "none", "Host/global plugin inheritance is on, but no host plugin dirs are configured.");
|
|
210
|
+
return applied("hostAssets.plugins", `${a.hostPluginDirs.length}`, `Host/global plugin dirs passed to ${label} (${a.hostPluginDirs.join(", ")}).`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function provisioningMcpEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
214
|
+
const names = a.mcp.servers;
|
|
215
|
+
if (!names.length) return notApplicable("provisioning.mcp", "none", "No relay-provisioned MCP servers materialized for this launch.");
|
|
216
|
+
const count = `${names.length} server${names.length === 1 ? "" : "s"}`;
|
|
217
|
+
const providerLabel = getManifest(a.provider)?.label ?? a.provider;
|
|
218
|
+
return applied("provisioning.mcp", count, `Relay-provisioned MCP servers injected for ${providerLabel} (${names.join(", ")})${a.mcp.strict ? "; strict mode guarantees only declared servers load" : ""}.`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function provisioningSkippedEntries(a: AssembledLaunch): AgentProfileProjectionEntry[] {
|
|
222
|
+
return (a.profile?.provisioning?.skipped ?? []).map((item) => partial(
|
|
223
|
+
`provisioning.${item.kind}.${item.ref}`,
|
|
224
|
+
item.reason,
|
|
225
|
+
item.detail,
|
|
226
|
+
));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// #667 — project `.mcp.json` projection provenance. `not-applicable` when the profile/spawn
|
|
230
|
+
// didn't opt in (the default); `applied` lists the spawn-cwd servers relay injected through
|
|
231
|
+
// the controlled --mcp-config / -c path (sourced from the project, not ambient host MCP).
|
|
232
|
+
function projectMcpEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
233
|
+
const optedIn = Boolean(a.profile?.projectMcp);
|
|
234
|
+
const names = a.mcp.projectServers;
|
|
235
|
+
if (!optedIn) return notApplicable("projectMcp", "off", "Project .mcp.json projection is off (opt in via the projectMcp profile/spawn option).");
|
|
236
|
+
if (!names.length) return applied("projectMcp", "none", "Project .mcp.json projection is on, but the spawn cwd declared no injectable MCP servers.");
|
|
237
|
+
const count = `${names.length} server${names.length === 1 ? "" : "s"}`;
|
|
238
|
+
return applied("projectMcp", count, `Project .mcp.json servers injected for this launch (${names.join(", ")})${a.mcp.strict ? "; survives strict MCP mode" : ""}.`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function projectSkillsEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
242
|
+
const optedIn = Boolean(a.profile?.projectSkills);
|
|
243
|
+
if (!optedIn) return notApplicable("projectSkills", "off", "Project .claude/skills projection is off (opt in via the projectSkills profile/spawn option).");
|
|
244
|
+
if (!getManifest(a.provider)?.provisioning?.bundledPlugin) return notApplicable("projectSkills", "unsupported", "Project skills projection applies to plugin-capable providers only.");
|
|
245
|
+
if (!a.projectSkills.length) return applied("projectSkills", "none", "Project .claude/skills projection is on, but the spawn cwd declared no valid skill dirs.");
|
|
246
|
+
const names = a.projectSkills.map((s) => s.name).join(", ");
|
|
247
|
+
return applied("projectSkills", `${a.projectSkills.length}`, `Project .claude skills materialized into Relay's managed Claude config home (${names}); host/global skills are excluded.`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function projectSettingsEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
251
|
+
const optedIn = Boolean(a.profile?.projectSettings);
|
|
252
|
+
if (!optedIn) return notApplicable("projectSettings", "off", "Project .claude/settings.json projection is off (opt in via the projectSettings profile/spawn option).");
|
|
253
|
+
if (!getManifest(a.provider)?.provisioning?.bundledPlugin) return notApplicable("projectSettings", "unsupported", "Project settings projection applies to plugin-capable providers only.");
|
|
254
|
+
const ignored = a.projectSettings.ignoredKeys.length ? `; ignored security keys: ${a.projectSettings.ignoredKeys.join(", ")}` : "";
|
|
255
|
+
return applied("projectSettings", a.projectSettings.keys.length ? `${a.projectSettings.keys.length} keys` : "none", `Project .claude/settings.json was sanitized and injected through --settings; Relay approvalMode/permission gates remain authoritative${ignored}.`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// #672/#689 — shared host-listener MCP provenance. `applied` reports the per-agent `callmux
|
|
259
|
+
// bridge` route. `not-applicable` means the resolved profile kept shared MCP off (for example a
|
|
260
|
+
// zero-host profile, explicit false, or global kill-switch normalization before launch).
|
|
261
|
+
function sharedMcpEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
262
|
+
const optedIn = Boolean(a.profile?.sharedMcp);
|
|
263
|
+
const listener = a.mcp.sharedListener;
|
|
264
|
+
if (!optedIn || !listener) return notApplicable("sharedMcp", "off", "Shared host-listener MCP is off for this resolved profile; non-identity MCP is injected per-agent.");
|
|
265
|
+
return applied("sharedMcp", "on", `Non-identity MCP (e.g. tokenlean, github) routed through the shared callmux listener (${listener.url}) via a per-agent 'callmux bridge --cwd "$WORKTREE"'; session survives a listener restart, session-cwd isolated. Relay endpoint stays per-agent.`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function globalInstructionsEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
269
|
+
const disposition = a.instructions.global;
|
|
270
|
+
if (disposition === "allow") return applied("instructions.global", "allow", "Host/global provider instructions are left available.");
|
|
271
|
+
if (disposition === "isolated") return applied("instructions.global", "ignore", `${a.provider} uses an isolated provider config home, so host/global provider instructions are not loaded.`);
|
|
272
|
+
return unsupported("instructions.global", "ignore", `${a.provider} global instruction isolation requires an isolated provider config home.`);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function mcpEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
276
|
+
const mode = a.profile?.mcp.mode ?? "host";
|
|
277
|
+
if (mode === "host") return applied("mcp", "host", "Host provider MCP configuration is left available.");
|
|
278
|
+
if (mode === "none" && a.base !== "host") {
|
|
279
|
+
return applied("mcp", "none", `${a.provider} uses an isolated provider config home without host MCP configuration.`);
|
|
280
|
+
}
|
|
281
|
+
return unsupported("mcp", mode, `${a.provider} MCP category projection is not enforced yet.`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function hooksEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
285
|
+
const mode = a.profile?.hooks.mode ?? "host";
|
|
286
|
+
if (mode === "host") return applied("hooks", "host", "Host provider hooks are left available.");
|
|
287
|
+
if (mode === "none" && a.base !== "host") {
|
|
288
|
+
return applied("hooks", "none", `${a.provider} uses an isolated provider config home without host hook configuration.`);
|
|
289
|
+
}
|
|
290
|
+
return unsupported("hooks", mode, `${a.provider} hook category projection is not enforced yet.`);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function filesystemEntry(profile: AgentProfile): AgentProfileProjectionEntry {
|
|
294
|
+
if (profile.permissions.filesystem === "host") return applied("permissions.filesystem", "host", "No profile-level filesystem boundary requested.");
|
|
295
|
+
return partial("permissions.filesystem", profile.permissions.filesystem, "Relay constrains spawn cwd through the orchestrator; provider-level filesystem sandbox projection is not complete yet.");
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function configHomeEntry(a: AssembledLaunch): AgentProfileProjectionEntry {
|
|
299
|
+
if (!a.configHome) return applied("provider.configHome", "host", "Provider uses the host's normal configuration home.");
|
|
300
|
+
return applied("provider.configHome", a.base, `${a.provider} is launched with an Agent Relay managed provider config home and linked host auth where available.`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function envEntry(profile: AgentProfile): AgentProfileProjectionEntry {
|
|
304
|
+
const count = Object.keys(profile.env).length;
|
|
305
|
+
return count
|
|
306
|
+
? applied("env", `${count} vars`, "Profile environment variables are passed through the orchestrator runner environment.")
|
|
307
|
+
: applied("env", "none", "No profile environment variables requested.");
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function applied(capability: string, requested: string, detail: string): AgentProfileProjectionEntry {
|
|
311
|
+
return { capability, requested, result: "applied", detail };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function partial(capability: string, requested: string, detail: string): AgentProfileProjectionEntry {
|
|
315
|
+
return { capability, requested, result: "partial", detail };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function unsupported(capability: string, requested: string, detail: string): AgentProfileProjectionEntry {
|
|
319
|
+
return { capability, requested, result: "unsupported", detail };
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function notApplicable(capability: string, requested: string, detail: string): AgentProfileProjectionEntry {
|
|
323
|
+
return { capability, requested, result: "not-applicable", detail };
|
|
324
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SpawnProvider } from "agent-relay-sdk";
|
|
2
|
+
import type { ProviderAdapter } from "./adapter";
|
|
3
|
+
import { ClaudeAdapter } from "./adapters/claude";
|
|
4
|
+
import { CodexAdapter } from "./adapters/codex";
|
|
5
|
+
|
|
6
|
+
interface RunnerProviderRegistration {
|
|
7
|
+
provider: SpawnProvider;
|
|
8
|
+
createAdapter: () => ProviderAdapter;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const RUNNER_PROVIDERS: Record<string, RunnerProviderRegistration> = {
|
|
12
|
+
claude: { provider: "claude", createAdapter: () => new ClaudeAdapter() },
|
|
13
|
+
codex: { provider: "codex", createAdapter: () => new CodexAdapter() },
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function createProviderAdapter(provider: SpawnProvider): ProviderAdapter {
|
|
17
|
+
const registration = RUNNER_PROVIDERS[provider];
|
|
18
|
+
if (!registration) throw new Error(`unsupported provider adapter: ${provider}`);
|
|
19
|
+
return registration.createAdapter();
|
|
20
|
+
}
|