@akira-tl/forgerelay 1.2.0-rc.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/server.js +21 -3
- package/dist/workspaces/presentation/workspace-presentation.js +21 -0
- package/dist/workspaces/relay/tests/test-support.js +1 -0
- package/package.json +2 -2
- package/scripts/debug/relay-accept/support.mjs +32 -0
- package/scripts/debug/relay-accept.mjs +15 -14
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable ForgeRelay changes are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.2.1] - 2026-09-13
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Reconstruct relayed and Composite Workspace Panel presentation from durable Workspace state across modern/stateless MCP requests, preventing the ChatGPT Activity Panel from remaining on `Waiting...` after a relayed `open_workspace`; closed Workspaces remain non-renderable.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Added Composite + Relay execution-context coverage to the authoritative `workspace-mcp` test shard, with Shell Instructions enabled explicitly where that opt-in behavior is under test.
|
|
16
|
+
|
|
17
|
+
## [1.2.0] - 2026-09-13
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Promoted the accepted Config System v2 release candidate to stable `1.2.0` without changing product behavior from `1.2.0-rc.1`; stable publication reuses the same cross-platform verified-artifact release path and moves the npm stable channel to `latest` only after fresh, upgrade, migration, and packaged-runtime acceptance pass.
|
|
22
|
+
|
|
7
23
|
## [1.2.0-rc.1] - 2026-09-13
|
|
8
24
|
|
|
9
25
|
### Added
|
package/dist/server.js
CHANGED
|
@@ -30,7 +30,7 @@ import { formatPathForPrompt } from "./workspaces/resources/skills.js";
|
|
|
30
30
|
import { WorkspaceTaskReminderTracker } from "./workspaces/tasks/workspace-task-reminders.js";
|
|
31
31
|
import { WorkspaceTaskStore } from "./workspaces/tasks/workspace-tasks.js";
|
|
32
32
|
import { WorkspaceCheckpointStore } from "./workspaces/state/workspace-checkpoints.js";
|
|
33
|
-
import { compactWorkspacePresentation } from "./workspaces/presentation/workspace-presentation.js";
|
|
33
|
+
import { compactCompositeWorkspacePresentation, compactRelayedWorkspacePresentation, compactWorkspacePresentation, } from "./workspaces/presentation/workspace-presentation.js";
|
|
34
34
|
import { formatAgentsPath } from "./workspaces.js";
|
|
35
35
|
import { summarizeSubagentProfile } from "./subagents/profiles.js";
|
|
36
36
|
import { formatSubagentProviderAvailabilitySummary } from "./subagents/providers/availability.js";
|
|
@@ -442,8 +442,26 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
442
442
|
};
|
|
443
443
|
const workspacePanelState = async (workspaceId) => {
|
|
444
444
|
const remembered = workspacePanelStates.get(workspaceId);
|
|
445
|
-
if (
|
|
446
|
-
|
|
445
|
+
if (compositeWorkspaces.has(workspaceId)) {
|
|
446
|
+
if (remembered)
|
|
447
|
+
return remembered;
|
|
448
|
+
const composite = compositeWorkspaces.get(workspaceId);
|
|
449
|
+
return composite.status === "active"
|
|
450
|
+
? compactCompositeWorkspacePresentation(composite)
|
|
451
|
+
: undefined;
|
|
452
|
+
}
|
|
453
|
+
if (remoteWorkspaces.has(workspaceId)) {
|
|
454
|
+
if (remembered)
|
|
455
|
+
return remembered;
|
|
456
|
+
try {
|
|
457
|
+
const inspected = await remoteWorkspaces.inspectWorkspace(workspaceId);
|
|
458
|
+
return inspected.status === "closed" || inspected.state === "closed"
|
|
459
|
+
? undefined
|
|
460
|
+
: compactRelayedWorkspacePresentation(inspected);
|
|
461
|
+
}
|
|
462
|
+
catch {
|
|
463
|
+
return undefined;
|
|
464
|
+
}
|
|
447
465
|
}
|
|
448
466
|
try {
|
|
449
467
|
const workspace = workspaces.getWorkspace(workspaceId);
|
|
@@ -37,6 +37,27 @@ export function compactWorkspacePresentation(card) {
|
|
|
37
37
|
presentation.presentationRevision = presentationRevision(card, presentation);
|
|
38
38
|
return presentation;
|
|
39
39
|
}
|
|
40
|
+
export function compactCompositeWorkspacePresentation(composite) {
|
|
41
|
+
return compactWorkspacePresentation({
|
|
42
|
+
workspaceId: composite.id,
|
|
43
|
+
kind: "composite",
|
|
44
|
+
name: composite.name,
|
|
45
|
+
path: composite.name,
|
|
46
|
+
members: composite.members,
|
|
47
|
+
summary: { members: composite.members.length, status: composite.status },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export function compactRelayedWorkspacePresentation(inspected) {
|
|
51
|
+
return compactWorkspacePresentation({
|
|
52
|
+
workspaceId: inspected.workspaceId,
|
|
53
|
+
kind: inspected.kind,
|
|
54
|
+
root: inspected.root,
|
|
55
|
+
path: inspected.root,
|
|
56
|
+
mode: inspected.mode,
|
|
57
|
+
sourceRoot: inspected.sourceRoot,
|
|
58
|
+
summary: { mode: inspected.mode, relay: inspected.relay },
|
|
59
|
+
});
|
|
60
|
+
}
|
|
40
61
|
function projectExecutionContext(value) {
|
|
41
62
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
42
63
|
return undefined;
|
|
@@ -68,6 +68,7 @@ export async function startForge(t, options) {
|
|
|
68
68
|
...(options.taskReminderInterval !== undefined ? { taskReminderInterval: options.taskReminderInterval } : {}),
|
|
69
69
|
...(options.mediaMaxBytes !== undefined ? { mediaMaxBytes: options.mediaMaxBytes } : {}),
|
|
70
70
|
...(options.mcpServers ? { mcpServers: options.mcpServers } : {}),
|
|
71
|
+
...(options.shellInstructions !== undefined ? { shellInstructions: options.shellInstructions } : {}),
|
|
71
72
|
...(options.hooks ? { hooks: options.hooks } : {}),
|
|
72
73
|
}, null, 2));
|
|
73
74
|
const env = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akira-tl/forgerelay",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Local development control plane for MCP coding agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://github.com/Akira-TL/forgerelay#readme",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"release:push-ready": "node scripts/release/push-ready.mjs",
|
|
68
68
|
"postinstall": "node scripts/fix-node-pty-permissions.mjs",
|
|
69
69
|
"start": "node dist/cli.js serve",
|
|
70
|
-
"test": "node --test scripts/debug/runtime.test.mjs scripts/config/schema-text.test.mjs scripts/release-proof.test.mjs scripts/release/release-gate.test.mjs scripts/release/push-ready.test.mjs scripts/release/release-version.test.mjs && tsx src/mcp/oauth/router.test.ts && tsx src/workspaces/relay/auth/remote-auth-cli.test.ts && tsx src/workspaces/relay/auth/remote-ssh-auth-cli.test.ts && tsx src/workspaces/relay/tests/lifecycle.test.ts && tsx src/workspaces/relay/tests/routing.test.ts && tsx src/workspaces/relay/tests/ssh.test.ts && tsx src/workspaces/relay/tests/process.test.ts && tsx src/workspaces/relay/tests/recovery.test.ts && tsx src/workspaces/relay/tests/checkpoint.test.ts && tsx src/runtime/config/definition/schema.test.ts && tsx src/runtime/config/resolution/resolver.test.ts && tsx src/runtime/security/project-execution-trust.test.ts && tsx src/runtime/config/resolution/hooks.test.ts && tsx src/workspaces/state/project-context.test.ts && tsx src/runtime/config/config.test.ts && tsx src/runtime/config/external-mcp-registry.test.ts && tsx src/runtime/config/external-mcp-auth-store.test.ts && tsx src/mcp/operations/external-mcp/external-mcp-oauth.test.ts && tsx src/cli/mcp/status.test.ts && tsx src/cli/mcp/diagnostics.test.ts && tsx src/cli/mcp/external-mcp.test.ts && tsx src/runtime/shell/command-shell-runtime.test.ts && tsx src/runtime/instructions/shell-instructions.test.ts && tsx src/runtime/instructions/powershell-skill.test.ts && tsx src/cli/shell/setup.test.ts && tsx src/lsp/language-server-config.test.ts && tsx src/lsp/runtime/managed-language-servers.test.ts && tsx src/lsp/normalization/hover.test.ts && tsx src/lsp/references.server.test.ts && tsx src/lsp/operations/document-symbols.server.test.ts && tsx src/lsp/operations/workspace-symbols.server.test.ts && tsx src/lsp/operations/diagnostics-push.server.test.ts && tsx src/lsp/operations/diagnostics-pull.server.test.ts && tsx src/lsp/operations/request-hardening.server.test.ts && tsx src/lsp/operations/recovery.server.test.ts && tsx src/lsp/operations/lifecycle.server.test.ts && tsx src/lsp/operations/project-trust.server.test.ts && tsx src/lsp/runtime/semantic-requests.test.ts && tsx src/runtime/logging/logger.test.ts && tsx src/runtime/logging/proxy-trust.test.ts && tsx src/runtime/state/lock/file-lock.test.ts && tsx src/runtime/state/runtime-lease.test.ts && tsx src/mcp/panel/mcp-app-template.test.ts && tsx src/mcp/hooks/hooks.test.ts && tsx src/mcp/hooks/hooks-trust.test.ts && tsx src/mcp/operations/external-mcp/external-mcp-transform.test.ts && tsx src/mcp/hooks/external-mcp-transform-trust.test.ts && tsx src/mcp/operations/external-mcp/external-mcp-trust.test.ts && tsx src/mcp/server/core/capability-registry.test.ts && tsx src/mcp/server-instructions.test.ts && tsx src/mcp/request-context.test.ts && tsx src/mcp/request-meta.test.ts && tsx src/mcp/artifacts/incoming-artifacts.test.ts && tsx src/mcp/artifacts/artifact-download.test.ts && tsx src/ui/core/card-types.test.ts && tsx src/ui/activity/model.test.ts && tsx src/ui/activity/detail-card.test.ts && tsx src/ui/review/patch-display.test.ts && tsx src/ui/core/tool-display.test.ts && tsx src/mcp/filesystem/apply-patch.test.ts && tsx src/mcp/process/process-platform.test.ts && tsx src/mcp/process/process-sessions.test.ts && tsx src/mcp/server/transport/mcp-sessions.test.ts && tsx src/mcp/server/transport/server-shutdown.test.ts && tsx src/mcp/server/operations/mutation-diagnostics.test.ts && tsx src/mcp/server/operations/hooks.test.ts && tsx src/subagents/providers/adapters/codex.test.ts && tsx src/subagents/providers/adapters/pi.test.ts && tsx src/subagents/providers/registry.test.ts && tsx src/subagents/providers/availability.test.ts && tsx src/subagents/profiles.test.ts && tsx src/subagents/cli-target.test.ts && tsx src/subagents/sessions/store.test.ts && tsx src/subagents/sessions/manager.test.ts && tsx src/subagents/sessions/project-trust.test.ts && tsx src/subagents/sessions/mcp/capability.server.test.ts && tsx src/subagents/sessions/mcp/continuation.server.test.ts && tsx src/subagents/sessions/mcp/lifecycle.server.test.ts && tsx src/subagents/sessions/mcp/reconciliation.server.test.ts && tsx src/subagents/sessions/mcp/routing.server.test.ts && tsx src/mcp/filesystem/roots.test.ts && tsx src/mcp/filesystem/file-mutations.test.ts && tsx src/mcp/operations/edit-preflight.test.ts && tsx src/workspaces/resources/skills.test.ts && tsx src/runtime/state/db/migrations.test.ts && tsx src/workspaces/state/workspace-store.test.ts && tsx src/workspaces/tasks/workspace-tasks.test.ts && tsx src/workspaces/tasks/workspace-task-reminders.test.ts && tsx src/activity/history/audit-store.test.ts && tsx src/activity/history/bash-output-store.test.ts && tsx src/activity/runtime/lifecycle.test.ts && tsx src/activity/history/query-service.test.ts && tsx src/mcp/operations/core-operation-executor.test.ts && tsx src/mcp/operations/bulk-mutation.test.ts && tsx src/mcp/operations/batch/scheduler.test.ts && tsx src/mcp/operations/batch/executor-policy.test.ts && tsx src/workspaces.test.ts && tsx src/workspaces/conversation-checkout.test.ts && tsx src/workspaces/conversation-worktree.test.ts && tsx src/workspaces/git/worktree-recovery.test.ts && tsx src/mcp/server/workspace/workspace-inventory.test.ts && tsx src/mcp/server/workspace/workspace-recovery.test.ts && tsx src/mcp/server/workspace/workspace-checkpoint.test.ts && tsx src/workspaces/review/review-checkpoints.test.ts && tsx src/lsp/code-intelligence.server.test.ts && npm run build:app && tsx src/mcp/process/server.test.ts && tsx src/mcp/panel/server.test.ts && tsx src/mcp/server/server.test.ts && tsx src/mcp/oauth/oauth-store.test.ts && tsx src/cli/maintenance.test.ts && tsx src/cli/maintenance-prune.test.ts && tsx src/cli/cli.test.ts",
|
|
70
|
+
"test": "node --test scripts/debug/runtime.test.mjs scripts/config/schema-text.test.mjs scripts/release-proof.test.mjs scripts/release/release-gate.test.mjs scripts/release/push-ready.test.mjs scripts/release/release-version.test.mjs && tsx src/mcp/oauth/router.test.ts && tsx src/workspaces/relay/auth/remote-auth-cli.test.ts && tsx src/workspaces/relay/auth/remote-ssh-auth-cli.test.ts && tsx src/workspaces/relay/tests/lifecycle.test.ts && tsx src/workspaces/relay/tests/routing.test.ts && tsx src/workspaces/relay/tests/ssh.test.ts && tsx src/workspaces/relay/tests/process.test.ts && tsx src/workspaces/relay/tests/recovery.test.ts && tsx src/workspaces/relay/tests/checkpoint.test.ts && tsx src/workspaces/relay/tests/composite.test.ts && tsx src/runtime/config/definition/schema.test.ts && tsx src/runtime/config/resolution/resolver.test.ts && tsx src/runtime/security/project-execution-trust.test.ts && tsx src/runtime/config/resolution/hooks.test.ts && tsx src/workspaces/state/project-context.test.ts && tsx src/runtime/config/config.test.ts && tsx src/runtime/config/external-mcp-registry.test.ts && tsx src/runtime/config/external-mcp-auth-store.test.ts && tsx src/mcp/operations/external-mcp/external-mcp-oauth.test.ts && tsx src/cli/mcp/status.test.ts && tsx src/cli/mcp/diagnostics.test.ts && tsx src/cli/mcp/external-mcp.test.ts && tsx src/runtime/shell/command-shell-runtime.test.ts && tsx src/runtime/instructions/shell-instructions.test.ts && tsx src/runtime/instructions/powershell-skill.test.ts && tsx src/cli/shell/setup.test.ts && tsx src/lsp/language-server-config.test.ts && tsx src/lsp/runtime/managed-language-servers.test.ts && tsx src/lsp/normalization/hover.test.ts && tsx src/lsp/references.server.test.ts && tsx src/lsp/operations/document-symbols.server.test.ts && tsx src/lsp/operations/workspace-symbols.server.test.ts && tsx src/lsp/operations/diagnostics-push.server.test.ts && tsx src/lsp/operations/diagnostics-pull.server.test.ts && tsx src/lsp/operations/request-hardening.server.test.ts && tsx src/lsp/operations/recovery.server.test.ts && tsx src/lsp/operations/lifecycle.server.test.ts && tsx src/lsp/operations/project-trust.server.test.ts && tsx src/lsp/runtime/semantic-requests.test.ts && tsx src/runtime/logging/logger.test.ts && tsx src/runtime/logging/proxy-trust.test.ts && tsx src/runtime/state/lock/file-lock.test.ts && tsx src/runtime/state/runtime-lease.test.ts && tsx src/mcp/panel/mcp-app-template.test.ts && tsx src/mcp/hooks/hooks.test.ts && tsx src/mcp/hooks/hooks-trust.test.ts && tsx src/mcp/operations/external-mcp/external-mcp-transform.test.ts && tsx src/mcp/hooks/external-mcp-transform-trust.test.ts && tsx src/mcp/operations/external-mcp/external-mcp-trust.test.ts && tsx src/mcp/server/core/capability-registry.test.ts && tsx src/mcp/server-instructions.test.ts && tsx src/mcp/request-context.test.ts && tsx src/mcp/request-meta.test.ts && tsx src/mcp/artifacts/incoming-artifacts.test.ts && tsx src/mcp/artifacts/artifact-download.test.ts && tsx src/ui/core/card-types.test.ts && tsx src/ui/activity/model.test.ts && tsx src/ui/activity/detail-card.test.ts && tsx src/ui/review/patch-display.test.ts && tsx src/ui/core/tool-display.test.ts && tsx src/mcp/filesystem/apply-patch.test.ts && tsx src/mcp/process/process-platform.test.ts && tsx src/mcp/process/process-sessions.test.ts && tsx src/mcp/server/transport/mcp-sessions.test.ts && tsx src/mcp/server/transport/server-shutdown.test.ts && tsx src/mcp/server/operations/mutation-diagnostics.test.ts && tsx src/mcp/server/operations/hooks.test.ts && tsx src/subagents/providers/adapters/codex.test.ts && tsx src/subagents/providers/adapters/pi.test.ts && tsx src/subagents/providers/registry.test.ts && tsx src/subagents/providers/availability.test.ts && tsx src/subagents/profiles.test.ts && tsx src/subagents/cli-target.test.ts && tsx src/subagents/sessions/store.test.ts && tsx src/subagents/sessions/manager.test.ts && tsx src/subagents/sessions/project-trust.test.ts && tsx src/subagents/sessions/mcp/capability.server.test.ts && tsx src/subagents/sessions/mcp/continuation.server.test.ts && tsx src/subagents/sessions/mcp/lifecycle.server.test.ts && tsx src/subagents/sessions/mcp/reconciliation.server.test.ts && tsx src/subagents/sessions/mcp/routing.server.test.ts && tsx src/mcp/filesystem/roots.test.ts && tsx src/mcp/filesystem/file-mutations.test.ts && tsx src/mcp/operations/edit-preflight.test.ts && tsx src/workspaces/resources/skills.test.ts && tsx src/runtime/state/db/migrations.test.ts && tsx src/workspaces/state/workspace-store.test.ts && tsx src/workspaces/tasks/workspace-tasks.test.ts && tsx src/workspaces/tasks/workspace-task-reminders.test.ts && tsx src/activity/history/audit-store.test.ts && tsx src/activity/history/bash-output-store.test.ts && tsx src/activity/runtime/lifecycle.test.ts && tsx src/activity/history/query-service.test.ts && tsx src/mcp/operations/core-operation-executor.test.ts && tsx src/mcp/operations/bulk-mutation.test.ts && tsx src/mcp/operations/batch/scheduler.test.ts && tsx src/mcp/operations/batch/executor-policy.test.ts && tsx src/workspaces.test.ts && tsx src/workspaces/conversation-checkout.test.ts && tsx src/workspaces/conversation-worktree.test.ts && tsx src/workspaces/git/worktree-recovery.test.ts && tsx src/mcp/server/workspace/workspace-inventory.test.ts && tsx src/mcp/server/workspace/workspace-recovery.test.ts && tsx src/mcp/server/workspace/workspace-checkpoint.test.ts && tsx src/workspaces/review/review-checkpoints.test.ts && tsx src/lsp/code-intelligence.server.test.ts && npm run build:app && tsx src/mcp/process/server.test.ts && tsx src/mcp/panel/server.test.ts && tsx src/mcp/server/server.test.ts && tsx src/mcp/oauth/oauth-store.test.ts && tsx src/cli/maintenance.test.ts && tsx src/cli/maintenance-prune.test.ts && tsx src/cli/cli.test.ts",
|
|
71
71
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
72
72
|
"release:check": "node scripts/release-version.mjs check",
|
|
73
73
|
"release:tag-check": "node scripts/release-version.mjs tag",
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from "node:fs";
|
|
14
14
|
import { join, resolve } from "node:path";
|
|
15
15
|
import { setTimeout as delay } from "node:timers/promises";
|
|
16
|
+
import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/client";
|
|
16
17
|
import { debugRoot, repoRoot } from "../runtime.mjs";
|
|
17
18
|
|
|
18
19
|
export function relayAcceptanceTopology() {
|
|
@@ -170,6 +171,37 @@ export function toolText(result) {
|
|
|
170
171
|
.join("\n");
|
|
171
172
|
}
|
|
172
173
|
|
|
174
|
+
export async function assertStatelessRelayPanel({ mcpUrl, accessToken, executionCheckout, expectedWorkspaceId }) {
|
|
175
|
+
const transport = new StreamableHTTPClientTransport(new URL(mcpUrl), {
|
|
176
|
+
requestInit: { headers: { authorization: `Bearer ${accessToken}` } },
|
|
177
|
+
});
|
|
178
|
+
const client = new Client(
|
|
179
|
+
{ name: "forgerelay-relay-stateless-acceptance", version: "1.0.0" },
|
|
180
|
+
{ versionNegotiation: { mode: { pin: "2026-07-28" } } },
|
|
181
|
+
);
|
|
182
|
+
try {
|
|
183
|
+
await client.connect(transport);
|
|
184
|
+
assert.equal(transport.sessionId, undefined);
|
|
185
|
+
const opened = await client.callTool({
|
|
186
|
+
name: "open_workspace",
|
|
187
|
+
arguments: { path: executionCheckout, relay: "execution", context: "none" },
|
|
188
|
+
});
|
|
189
|
+
assertToolOk(opened, "open relayed checkout over stateless HTTP");
|
|
190
|
+
assert.equal(opened.structuredContent.workspaceId, expectedWorkspaceId);
|
|
191
|
+
const panel = await client.callTool({
|
|
192
|
+
name: "activity_panel",
|
|
193
|
+
arguments: { workspaceId: expectedWorkspaceId },
|
|
194
|
+
_meta: { "dev.forgerelay/conversation": "relay-stateless-panel-acceptance" },
|
|
195
|
+
});
|
|
196
|
+
assertToolOk(panel, "render relayed Activity Panel over stateless HTTP");
|
|
197
|
+
assert.match(String(panel.structuredContent.turnId), /^turn_/);
|
|
198
|
+
assert.equal(panel._meta?.["forgerelay/activityPanelWorkspace"]?.workspaceId, expectedWorkspaceId);
|
|
199
|
+
} finally {
|
|
200
|
+
await client.close().catch(() => undefined);
|
|
201
|
+
}
|
|
202
|
+
pass("relay stateless Panel", "relayed open_workspace and activity_panel succeeded across modern stateless MCP requests");
|
|
203
|
+
}
|
|
204
|
+
|
|
173
205
|
export function pass(label, detail) {
|
|
174
206
|
console.log(`PASS ${label}: ${detail}`);
|
|
175
207
|
}
|
|
@@ -2,23 +2,19 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
import { spawn, spawnSync } from "node:child_process";
|
|
3
3
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
4
4
|
import { once } from "node:events";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { join, resolve } from "node:path";
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
8
7
|
import { setTimeout as delay } from "node:timers/promises";
|
|
9
|
-
import {
|
|
10
|
-
import { relayAcceptanceTopology, assertPortsFree, setupGitProject,
|
|
11
|
-
|
|
8
|
+
import { repoRoot } from "./runtime.mjs";
|
|
9
|
+
import { relayAcceptanceTopology, assertPortsFree, setupGitProject, findTaskStateFile, assertTaskBodyAbsentFromGateway, assertSafeRelayInspection, installRelayImageFixture, assertRelayedImageResult, assertStatelessRelayPanel, assertToolOk, toolText, pass } from "./relay-accept/support.mjs";
|
|
12
10
|
const {
|
|
13
|
-
gatewayPort, executionPort, gatewayBaseUrl, gatewayMcpUrl, executionBaseUrl,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
bootstrapSecret, checkoutTaskBody, worktreeTaskBody, compositeMemberTaskBody, compositeTaskBody,
|
|
11
|
+
gatewayPort, executionPort, gatewayBaseUrl, gatewayMcpUrl, executionBaseUrl, acceptanceRoot,
|
|
12
|
+
gatewayConfigDir, gatewayStateDir, gatewayWorktreeRoot, gatewayProjects, gatewayLocalProject,
|
|
13
|
+
executionConfigDir, executionStateDir, executionWorktreeRoot, executionProjects, executionCheckout,
|
|
14
|
+
executionWorktreeSource, bootstrapSecret, checkoutTaskBody, worktreeTaskBody, compositeMemberTaskBody, compositeTaskBody,
|
|
18
15
|
} = relayAcceptanceTopology();
|
|
19
16
|
const gatewayOwnerToken = randomBytes(32).toString("base64url");
|
|
20
17
|
const executionOwnerToken = randomBytes(32).toString("base64url");
|
|
21
|
-
|
|
22
18
|
await assertPortsFree([gatewayPort, executionPort]);
|
|
23
19
|
rmSync(acceptanceRoot, { recursive: true, force: true });
|
|
24
20
|
mkdirSync(gatewayLocalProject, { recursive: true });
|
|
@@ -30,10 +26,8 @@ writeFileSync(join(gatewayLocalProject, "sentinel.txt"), "gateway-local-content\
|
|
|
30
26
|
writeFileSync(join(executionCheckout, "sentinel.txt"), "execution-remote-content\n");
|
|
31
27
|
writeFileSync(join(executionCheckout, "AGENTS.md"), `${bootstrapSecret}\n`);
|
|
32
28
|
setupGitProject(executionWorktreeSource);
|
|
33
|
-
|
|
34
29
|
writeAuthFile(gatewayConfigDir, gatewayOwnerToken, "relay-acceptance-gateway");
|
|
35
30
|
writeAuthFile(executionConfigDir, executionOwnerToken, "relay-acceptance-execution");
|
|
36
|
-
|
|
37
31
|
const executionEnv = instanceEnv({
|
|
38
32
|
port: executionPort,
|
|
39
33
|
baseUrl: executionBaseUrl,
|
|
@@ -106,6 +100,13 @@ try {
|
|
|
106
100
|
assert.equal(openedB.structuredContent.workspaceId, checkoutRelayId);
|
|
107
101
|
pass("relay persistent identity", `two Gateway conversations reused ${checkoutRelayId}`);
|
|
108
102
|
|
|
103
|
+
await assertStatelessRelayPanel({
|
|
104
|
+
mcpUrl: gatewayMcpUrl,
|
|
105
|
+
accessToken: oauth.accessToken,
|
|
106
|
+
executionCheckout,
|
|
107
|
+
expectedWorkspaceId: checkoutRelayId,
|
|
108
|
+
});
|
|
109
|
+
|
|
109
110
|
assertRelayedImageResult(callTool(gatewayMcpUrl, oauth.accessToken, sessionB, nextId(), "read", {
|
|
110
111
|
workspaceId: checkoutRelayId, path: "relay-image.png",
|
|
111
112
|
}, conversationB), relayImageBase64, gatewayStateDir);
|