Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
9e41774
Add thread ownership to projection threads
ccdwyer Jul 3, 2026
9fcfc71
Address slice-1 code review findings
ccdwyer Jul 3, 2026
581ae60
Add plugin host foundation
ccdwyer Jul 3, 2026
3e9c289
Address slice-2a-1 code review findings
ccdwyer Jul 3, 2026
8fd2056
Add plugin RPC transport and plugin-aware auth scopes
ccdwyer Jul 3, 2026
71a7da6
Address slice-2a-2 code review findings
ccdwyer Jul 3, 2026
ed58230
Add mechanical plugin capability facades
ccdwyer Jul 3, 2026
b50ca8c
Address slice-2a-3a code review findings
ccdwyer Jul 3, 2026
35ae33d
Add agents and vcs plugin capability facades
ccdwyer Jul 3, 2026
72f7a42
Add web plugin plumbing: bundle serving, import map, host shims
ccdwyer Jul 3, 2026
b5f2240
Format AgentsCapability review-fix edits
ccdwyer Jul 3, 2026
e12dcc4
Add PluginUiHost: load and render plugin web bundles
ccdwyer Jul 3, 2026
56910ad
Add plugin marketplace and install lifecycle (server)
ccdwyer Jul 3, 2026
215b7d6
Add Plugins marketplace UI, fixture plugin, and authoring docs
ccdwyer Jul 3, 2026
b7f029e
Add filesystem + httpClient plugin capabilities and palette wiring
ccdwyer Jul 3, 2026
d16c756
feat(workflow-boards): scaffold plugin package (slice A1a)
ccdwyer Jul 3, 2026
e3a72df
feat(workflow-boards): port 033 schema as p_workflow_boards_* migrati…
ccdwyer Jul 3, 2026
ff78eaa
test(workflow-boards): install integration test + schema-shape guard …
ccdwyer Jul 3, 2026
f4868c8
feat(plugins): expose raw SqlClient on the database capability (A1b e…
ccdwyer Jul 3, 2026
4ec062a
feat(workflow-boards): port workflow contracts module (slice A1b)
ccdwyer Jul 3, 2026
9bd4474
feat(workflow-boards): port event-sourcing core + NotificationSink (s…
ccdwyer Jul 3, 2026
5ca6ea2
test(workflow-boards): port event-sourcing-core tests onto plugin sch…
ccdwyer Jul 3, 2026
1a9c06b
style(workflow-boards): reformat A1a install integration test
ccdwyer Jul 3, 2026
846d621
feat(plugins): startTurn caller messageId/commandId + projections.rea…
ccdwyer Jul 3, 2026
b297e7a
feat(workflow-boards): add message_id column to dispatch outbox (A2 d…
ccdwyer Jul 3, 2026
a4f4d15
feat(workflow-boards): WorkflowAgentPort — durable turn dispatch/obse…
ccdwyer Jul 3, 2026
e26cd12
test(workflow-boards): WorkflowAgentPort port tests + fake agents cap…
ccdwyer Jul 3, 2026
a499cfb
feat(workflow-boards): WorkflowAgentPort.isPendingRequestLive + decla…
ccdwyer Jul 4, 2026
ee6600f
feat(workflow-boards): port WorkflowEngine + WorkflowRecovery onto A1…
ccdwyer Jul 4, 2026
be1eb21
test(workflow-boards): port WorkflowEngine + WorkflowRecovery test su…
ccdwyer Jul 4, 2026
2fff3c8
feat(plugins): expand sourceControl + vcs capabilities for PR-loop pa…
ccdwyer Jul 4, 2026
465c8ba
test(plugins): complete capability mocks for expanded sourceControl/v…
ccdwyer Jul 4, 2026
a283fe2
feat(plugin-host): surface capped stderr + realPath through vcs/fs ca…
ccdwyer Jul 4, 2026
f1b4261
feat(workflow-boards): port RealStepExecutor + step-type services ont…
ccdwyer Jul 4, 2026
2fa8b2e
feat(workflow-boards): port retention/worktree/thread/github-poller d…
ccdwyer Jul 4, 2026
f6955d4
feat(workflow-boards): mount the workflow runtime + wire recovery/dae…
ccdwyer Jul 4, 2026
2e1a8db
feat(workflow-boards): share the runtime + board-driving RPC surface …
ccdwyer Jul 4, 2026
dc7e7cc
test(plugins): install-and-drive-a-board E2E acceptance test (A4a)
ccdwyer Jul 4, 2026
2144de6
feat(workflow-boards): 16 board-management RPC methods (A4b-1)
ccdwyer Jul 4, 2026
8b1b6dd
test(plugins): extend the board E2E to cover board-management RPC (A4…
ccdwyer Jul 4, 2026
204721b
feat(workflow-boards): inbound webhook — http capability, WorkflowWeb…
ccdwyer Jul 4, 2026
9b61125
test(plugins): webhook E2E — install, token, ingest, no-oracle 404, d…
ccdwyer Jul 4, 2026
e4f7ec0
feat(workflow-boards): work-source connection foundation + secrets/ht…
ccdwyer Jul 4, 2026
dc7ce46
test(workflow-boards): work-source connection E2E + SSRF blocklist te…
ccdwyer Jul 4, 2026
a3c8497
feat(workflow-boards): GitHub/Asana/Jira work-source providers on the…
ccdwyer Jul 4, 2026
9a7f98f
test(workflow-boards): provider unit tests against a mocked httpClien…
ccdwyer Jul 4, 2026
4dee540
feat(workflow-boards): work-source sync daemon + import picker — fini…
ccdwyer Jul 4, 2026
0ac142c
test(workflow-boards): work-source import E2E + syncer start-ordering…
ccdwyer Jul 4, 2026
6c85867
fix(plugins): resolve host effect/SDK via nextResolve, not import.met…
ccdwyer Jul 4, 2026
97178ff
fix(workflow-boards): bundle json-logic-js into the plugin server bundle
ccdwyer Jul 4, 2026
73751a0
fix(plugins): ship pluginResolveHooks in the bundled server
ccdwyer Jul 4, 2026
341284f
fix(plugins): make the web plugin list self-heal on reconnect
ccdwyer Jul 4, 2026
430d0ec
feat(workflow-boards): web-bundle build scaffolding + Phase-0 smoke UI
ccdwyer Jul 4, 2026
c0e8300
feat(plugin-sdk-web): surface the host modules the board UI needs
ccdwyer Jul 4, 2026
7268fe5
feat(workflow-boards): plugin-local workflow data layer over the RPC …
ccdwyer Jul 4, 2026
d8e0179
docs(workflow-boards): turnkey B3 board-UI port plan
ccdwyer Jul 4, 2026
5d2a94d
feat(plugins): pass environmentId + search to plugin route components
ccdwyer Jul 4, 2026
1142f78
feat(workflow-boards): port the board UI into the plugin web bundle (B3)
ccdwyer Jul 4, 2026
bc5b70e
fix(workflow-boards): import effect from the barrel, not subpaths (we…
ccdwyer Jul 4, 2026
068d94e
feat(plugins): serve @t3tools/contracts as a host singleton for web p…
ccdwyer Jul 4, 2026
cdeb721
fix(plugins): emit the board plugin's Tailwind utilities in the host CSS
ccdwyer Jul 4, 2026
c4f4341
chore(plugins): remove the workflow-boards addon from core
ccdwyer Jul 4, 2026
8aa8585
feat(plugins): let plugins ship + the host inject their own CSS
ccdwyer Jul 5, 2026
37bc10f
fix(plugins): isolate injected plugin CSS in a lowest-priority cascad…
ccdwyer Jul 5, 2026
3f616cf
fix(plugins): register the `plugins` cascade layer in the HTML head
ccdwyer Jul 5, 2026
455091b
feat(plugins): serve plugin assets uncacheable in plugin dev mode
ccdwyer Jul 5, 2026
711faf0
feat(plugins): per-project sidebar action extension point + vcs/textG…
ccdwyer Jul 5, 2026
e3a2cb6
chore(plugins): sync pnpm-lock.yaml after rebase onto upstream/main
ccdwyer Jul 5, 2026
5d9ad21
fix(plugins): address automated PR review findings (#3699)
ccdwyer Jul 5, 2026
172ee7d
fix(plugins): second round of automated PR review findings (#3699)
ccdwyer Jul 5, 2026
b416af3
fix(plugins): round-3 PR review — interrupt-safe lifecycle, lock owne…
ccdwyer Jul 5, 2026
e0f6b62
fix(plugins): round-4 PR review — interrupt-isolated startup, semver …
ccdwyer Jul 5, 2026
9ae34ee
fix(plugins): round-5 PR review — typed activation-cancel sentinel, a…
ccdwyer Jul 5, 2026
67ca9e8
fix(plugins): round-6 PR review — strict cancel-only cause, determini…
ccdwyer Jul 5, 2026
b2e4df3
fix(plugins): round-7 PR review — activation single-flight, propagate…
ccdwyer Jul 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@ff-labs/fff-node": "0.9.4",
"@opencode-ai/sdk": "^1.3.15",
"@pierre/diffs": "catalog:",
"@t3tools/plugin-sdk": "workspace:*",
"effect": "catalog:",
"node-pty": "^1.1.0"
},
Expand Down
64 changes: 46 additions & 18 deletions apps/server/src/auth/EnvironmentAuth.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import * as NodeServices from "@effect/platform-node/NodeServices";
import { AuthAdministrativeScopes } from "@t3tools/contracts";
import {
AuthAdministrativeScopes,
AuthStandardClientScopes,
pluginReadScope,
} from "@t3tools/contracts";
import { expect, it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
Expand Down Expand Up @@ -89,13 +93,7 @@ it.layer(NodeServices.layer)("EnvironmentAuth.layer", (it) => {
);

expect(verified.sessionId.length).toBeGreaterThan(0);
expect(verified.scopes).toEqual([
"orchestration:read",
"orchestration:operate",
"terminal:operate",
"review:write",
"relay:read",
]);
expect(verified.scopes).toEqual(AuthStandardClientScopes);
expect(verified.subject).toBe("one-time-token");
}).pipe(Effect.provide(makeEnvironmentAuthLayer())),
);
Expand All @@ -117,6 +115,45 @@ it.layer(NodeServices.layer)("EnvironmentAuth.layer", (it) => {
}).pipe(Effect.provide(makeEnvironmentAuthLayer())),
);

it.effect("exchanges a standard-client grant for an implicitly-held plugin scope", () =>
Effect.gen(function* () {
const serverAuth = yield* EnvironmentAuth.EnvironmentAuth;
// A default pairing credential holds the standard-client marker, which
// implicitly satisfies every plugin scope even though `plugin:...:read`
// is not listed verbatim in the grant.
const pairingCredential = yield* serverAuth.issuePairingCredential();

const token = yield* serverAuth.exchangeBootstrapCredentialForAccessToken(
pairingCredential.credential,
[pluginReadScope("test-plugin")],
requestMetadata,
);

expect(token.scope).toBe("plugin:test-plugin:read");
}).pipe(Effect.provide(makeEnvironmentAuthLayer())),
);

it.effect("rejects a plugin-scope exchange when the grant is not a full standard client", () =>
Effect.gen(function* () {
const serverAuth = yield* EnvironmentAuth.EnvironmentAuth;
// A constrained grant that lacks the standard-client marker must NOT get
// implicit plugin access.
const pairingCredential = yield* serverAuth.issuePairingCredential({
scopes: ["orchestration:read"],
});

const error = yield* serverAuth
.exchangeBootstrapCredentialForAccessToken(
pairingCredential.credential,
[pluginReadScope("test-plugin")],
requestMetadata,
)
.pipe(Effect.flip);

expect(error._tag).toBe("ServerAuthScopeNotGrantedError");
}).pipe(Effect.provide(makeEnvironmentAuthLayer())),
);

it.effect("inherits a constrained pairing grant when token exchange omits scope", () =>
Effect.gen(function* () {
const serverAuth = yield* EnvironmentAuth.EnvironmentAuth;
Expand Down Expand Up @@ -167,16 +204,7 @@ it.layer(NodeServices.layer)("EnvironmentAuth.layer", (it) => {
makeCookieRequest(exchanged.sessionToken),
);

expect(verified.scopes).toEqual([
"orchestration:read",
"orchestration:operate",
"terminal:operate",
"review:write",
"relay:read",
"access:read",
"access:write",
"relay:write",
]);
expect(verified.scopes).toEqual(AuthAdministrativeScopes);
expect(verified.subject).toBe("administrative-bootstrap");
}).pipe(Effect.provide(makeEnvironmentAuthLayer())),
);
Expand Down
24 changes: 15 additions & 9 deletions apps/server/src/auth/EnvironmentAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import {
AuthAccessWriteScope,
AuthAdministrativeScopes,
AuthStandardClientScopes,
satisfiesScope,
type AuthAccessTokenResult,
type AuthBrowserSessionResult,
type AuthClientMetadata,
type AuthClientSession,
type AuthCreatePairingCredentialInput,
type AuthEnvironmentScope,
type AuthPairingLink,
type AuthPairingCredentialResult,
type AuthScope,
type AuthSessionId,
type AuthSessionState,
type ServerAuthDescriptor,
Expand Down Expand Up @@ -41,7 +42,7 @@ export const INTERNAL_ADMINISTRATIVE_BOOTSTRAP_SUBJECT = "administrative-bootstr
export interface IssuedPairingLink {
readonly id: string;
readonly credential: string;
readonly scopes: ReadonlyArray<AuthEnvironmentScope>;
readonly scopes: ReadonlyArray<AuthScope>;
readonly subject: string;
readonly label?: string;
readonly createdAt: DateTime.Utc;
Expand All @@ -52,7 +53,7 @@ export interface IssuedBearerSession {
readonly sessionId: AuthSessionId;
readonly token: string;
readonly method: "bearer-access-token";
readonly scopes: ReadonlyArray<AuthEnvironmentScope>;
readonly scopes: ReadonlyArray<AuthScope>;
readonly subject: string;
readonly client: AuthClientMetadata;
readonly expiresAt: DateTime.Utc;
Expand All @@ -62,7 +63,7 @@ export interface AuthenticatedSession {
readonly sessionId: AuthSessionId;
readonly subject: string;
readonly method: ServerAuthSessionMethod;
readonly scopes: ReadonlyArray<AuthEnvironmentScope>;
readonly scopes: ReadonlyArray<AuthScope>;
readonly proofKeyThumbprint?: string;
readonly expiresAt?: DateTime.DateTime;
}
Expand Down Expand Up @@ -423,7 +424,7 @@ export class EnvironmentAuth extends Context.Service<
>;
readonly exchangeBootstrapCredentialForAccessToken: (
credential: string,
requestedScopes: ReadonlyArray<AuthEnvironmentScope> | undefined,
requestedScopes: ReadonlyArray<AuthScope> | undefined,
requestMetadata: AuthClientMetadata,
input?: {
readonly proofKeyThumbprint?: string;
Expand All @@ -435,7 +436,7 @@ export class EnvironmentAuth extends Context.Service<
readonly createPairingLink: (input?: {
readonly ttl?: Duration.Duration;
readonly label?: string;
readonly scopes?: ReadonlyArray<AuthEnvironmentScope>;
readonly scopes?: ReadonlyArray<AuthScope>;
readonly subject?: string;
readonly proofKeyThumbprint?: string;
}) => Effect.Effect<IssuedPairingLink, ServerAuthInternalError>;
Expand All @@ -453,7 +454,7 @@ export class EnvironmentAuth extends Context.Service<
readonly issueSession: (input?: {
readonly ttl?: Duration.Duration;
readonly subject?: string;
readonly scopes?: ReadonlyArray<AuthEnvironmentScope>;
readonly scopes?: ReadonlyArray<AuthScope>;
readonly label?: string;
}) => Effect.Effect<IssuedBearerSession, ServerAuthInternalError>;
readonly listSessions: () => Effect.Effect<
Expand Down Expand Up @@ -694,7 +695,12 @@ export const make = Effect.gen(function* () {
Effect.flatMap((grant) =>
Effect.gen(function* () {
const grantedScopes = requestedScopes ?? grant.scopes;
if (!grantedScopes.every((scope) => grant.scopes.includes(scope))) {
// Downscope by implicit satisfaction, not verbatim membership: a
// full standard-client grant implicitly holds every plugin scope
// (and plugins:manage) via the standard-client marker, so requesting
// e.g. `plugin:<id>:read` against such a grant must succeed even
// though it is not listed literally in grant.scopes.
if (!grantedScopes.every((scope) => satisfiesScope(scope, grant.scopes))) {
return yield* new ServerAuthScopeNotGrantedError({});
}
return yield* sessions
Expand Down Expand Up @@ -743,7 +749,7 @@ export const make = Effect.gen(function* () {
);

const issuePairingCredentialForSubject = (input: {
readonly scopes: ReadonlyArray<AuthEnvironmentScope>;
readonly scopes: ReadonlyArray<AuthScope>;
readonly subject: string;
readonly label?: string;
}) =>
Expand Down
23 changes: 3 additions & 20 deletions apps/server/src/auth/EnvironmentAuthAdmin.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as NodeServices from "@effect/platform-node/NodeServices";
import { AuthAdministrativeScopes } from "@t3tools/contracts";
import { expect, it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
Expand Down Expand Up @@ -77,29 +78,11 @@ it.layer(NodeServices.layer)("EnvironmentAuth administrative operations", (it) =
const listedAfterRevoke = yield* environmentAuth.listSessions();

expect(issued.method).toBe("bearer-access-token");
expect(issued.scopes).toEqual([
"orchestration:read",
"orchestration:operate",
"terminal:operate",
"review:write",
"relay:read",
"access:read",
"access:write",
"relay:write",
]);
expect(issued.scopes).toEqual(AuthAdministrativeScopes);
expect(issued.client.deviceType).toBe("bot");
expect(issued.client.label).toBe("deploy-bot");
expect(verified.sessionId).toBe(issued.sessionId);
expect(verified.scopes).toEqual([
"orchestration:read",
"orchestration:operate",
"terminal:operate",
"review:write",
"relay:read",
"access:read",
"access:write",
"relay:write",
]);
expect(verified.scopes).toEqual(AuthAdministrativeScopes);
expect(verified.method).toBe("bearer-access-token");
expect(listedBeforeRevoke).toHaveLength(1);
expect(listedBeforeRevoke[0]?.sessionId).toBe(issued.sessionId);
Expand Down
59 changes: 42 additions & 17 deletions apps/server/src/auth/PairingGrantStore.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import * as NodeServices from "@effect/platform-node/NodeServices";
import {
AuthAdministrativeScopes,
AuthOrchestrationReadScope,
AuthStandardClientScopes,
pluginReadScope,
} from "@t3tools/contracts";
import { expect, it } from "@effect/vitest";
import * as Duration from "effect/Duration";
import * as Effect from "effect/Effect";
import * as Fiber from "effect/Fiber";
import * as Layer from "effect/Layer";
import * as Option from "effect/Option";
import * as Stream from "effect/Stream";
import * as TestClock from "effect/testing/TestClock";

import * as ServerConfig from "../config.ts";
Expand Down Expand Up @@ -74,13 +82,7 @@ it.layer(NodeServices.layer)("PairingGrantStore.layer", (it) => {
const second = yield* Effect.flip(bootstrapCredentials.consume(issued.credential));

expect(first.method).toBe("one-time-token");
expect(first.scopes).toEqual([
"orchestration:read",
"orchestration:operate",
"terminal:operate",
"review:write",
"relay:read",
]);
expect(first.scopes).toEqual(AuthStandardClientScopes);
expect(first.subject).toBe("one-time-token");
expect(first.label).toBe("Julius iPhone");
expect(issued.label).toBe("Julius iPhone");
Expand Down Expand Up @@ -145,16 +147,7 @@ it.layer(NodeServices.layer)("PairingGrantStore.layer", (it) => {
const third = yield* bootstrapCredentials.consume("desktop-bootstrap-token");

expect(first.method).toBe("desktop-bootstrap");
expect(first.scopes).toEqual([
"orchestration:read",
"orchestration:operate",
"terminal:operate",
"review:write",
"relay:read",
"access:read",
"access:write",
"relay:write",
]);
expect(first.scopes).toEqual(AuthAdministrativeScopes);
expect(first.subject).toBe("desktop-bootstrap");
expect(second.method).toBe("desktop-bootstrap");
expect(third.method).toBe("desktop-bootstrap");
Expand Down Expand Up @@ -218,6 +211,38 @@ it.layer(NodeServices.layer)("PairingGrantStore.layer", (it) => {
}).pipe(Effect.provide(makePairingGrantStoreLayer())),
);

it.effect("surfaces plugin scopes on listActive and the pairingLinkUpserted change event", () =>
Effect.scoped(
Effect.gen(function* () {
const bootstrapCredentials = yield* PairingGrantStore.PairingGrantStore;
const grantedScopes = [AuthOrchestrationReadScope, pluginReadScope("acme-notes")] as const;

const changesFiber = yield* Stream.take(bootstrapCredentials.streamChanges, 1).pipe(
Stream.runCollect,
Effect.forkChild,
);
yield* Effect.yieldNow;

const issued = yield* bootstrapCredentials.issueOneTimeToken({ scopes: grantedScopes });

// The active-link list carries the full granted scope set, not just
// the environment scopes.
const active = yield* bootstrapCredentials.listActive();
const listed = active.find((entry) => entry.id === issued.id);
expect(listed?.scopes).toEqual(grantedScopes);

// The change event mirrors it.
const changes = Array.from(yield* Fiber.join(changesFiber));
expect(changes).toHaveLength(1);
const change = changes[0]!;
expect(change.type).toBe("pairingLinkUpserted");
if (change.type === "pairingLinkUpserted") {
expect(change.pairingLink.scopes).toEqual(grantedScopes);
}
}),
).pipe(Effect.provide(makePairingGrantStoreLayer())),
);

it.effect("identifies consume-available failures and preserves their cause", () => {
const repositoryFailure = new PersistenceSqlError({
operation: "consume-pairing-link",
Expand Down
10 changes: 7 additions & 3 deletions apps/server/src/auth/PairingGrantStore.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
AuthAdministrativeScopes,
AuthStandardClientScopes,
type AuthEnvironmentScope,
type AuthScope,
type AuthPairingLink,
type ServerAuthBootstrapMethod,
} from "@t3tools/contracts";
Expand All @@ -22,7 +22,7 @@ import * as AuthPairingLinks from "../persistence/AuthPairingLinks.ts";

export interface BootstrapGrant {
readonly method: ServerAuthBootstrapMethod;
readonly scopes: ReadonlyArray<AuthEnvironmentScope>;
readonly scopes: ReadonlyArray<AuthScope>;
readonly subject: string;
readonly label?: string;
readonly proofKeyThumbprint?: string;
Expand Down Expand Up @@ -198,7 +198,7 @@ export class PairingGrantStore extends Context.Service<
{
readonly issueOneTimeToken: (input?: {
readonly ttl?: Duration.Duration;
readonly scopes?: ReadonlyArray<AuthEnvironmentScope>;
readonly scopes?: ReadonlyArray<AuthScope>;
readonly subject?: string;
readonly label?: string;
readonly proofKeyThumbprint?: string;
Expand Down Expand Up @@ -327,6 +327,8 @@ export const make = Effect.gen(function* () {
? ({
id: row.id,
credential: row.credential,
// Full persisted scopes (including plugin scopes) so granted
// capabilities are visible in the active-link list.
scopes: row.scopes,
subject: row.subject,
label: row.label,
Expand Down Expand Up @@ -408,6 +410,8 @@ export const make = Effect.gen(function* () {
yield* emitUpsert({
id,
credential,
// Emit the full granted scope set (including plugin scopes) on the
// `pairingLinkUpserted` change event.
scopes: input?.scopes ?? AuthStandardClientScopes,
subject: input?.subject ?? "one-time-token",
...(input?.label ? { label: input.label } : {}),
Expand Down
9 changes: 2 additions & 7 deletions apps/server/src/auth/SessionStore.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as NodeServices from "@effect/platform-node/NodeServices";
import { AuthStandardClientScopes } from "@t3tools/contracts";
import { expect, it } from "@effect/vitest";
import * as Duration from "effect/Duration";
import * as Effect from "effect/Effect";
Expand Down Expand Up @@ -140,13 +141,7 @@ it.layer(NodeServices.layer)("SessionStore.layer", (it) => {

expect(verified.method).toBe("bearer-access-token");
expect(verified.subject).toBe("test-clock");
expect(verified.scopes).toEqual([
"orchestration:read",
"orchestration:operate",
"terminal:operate",
"review:write",
"relay:read",
]);
expect(verified.scopes).toEqual(AuthStandardClientScopes);
}).pipe(Effect.provide(Layer.merge(makeSessionStoreLayer(), TestClock.layer()))),
);

Expand Down
Loading
Loading