Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
5081a1a
feat: add the execution-observer foundation (#12)
aryasaatvik Jun 13, 2026
f0cf727
feat: add the execution-history plugin (#13)
aryasaatvik Jun 13, 2026
94b50a2
feat: add the execution-metrics plugin (#14)
aryasaatvik Jun 13, 2026
e78112a
feat: JSON-document aggregation + keyset pagination pushdown (#15)
aryasaatvik Jun 14, 2026
9b5e223
feat(execution-history): keyset runs API with aggregate meta (#16)
aryasaatvik Jun 14, 2026
58f7780
feat(execution-history): openstatus-style runs UI (#17)
aryasaatvik Jun 14, 2026
008d611
fix(execution-history): align runs columns and slim timeline bars (#18)
aryasaatvik Jun 14, 2026
39bf0b1
feat(execution-history): rich run-detail drawer (#19)
aryasaatvik Jun 14, 2026
6cba288
fix(execution-history): pad the runs toolbar
aryasaatvik Jun 14, 2026
391e431
feat(execution-history): attribute runs to a trigger actor + filter b…
aryasaatvik Jun 14, 2026
1d6ef75
feat(execution-history): restore parity gaps from the old runs UI (#21)
aryasaatvik Jun 14, 2026
7c77922
feat(host-cloudflare): attribute MCP-session runs to a trigger actor …
aryasaatvik Jun 14, 2026
75a2273
fix(execution-history): tolerate runs stored before the actor fields …
aryasaatvik Jun 14, 2026
3e3bb25
feat(execution-history): horizontal-scroll runs table instead of hidi…
aryasaatvik Jun 14, 2026
2df54b2
chore(selfhost): use peerDependencies for shared singletons
aryasaatvik Jun 10, 2026
676ef1c
feat(sdk): read org plugin-storage outside the runtime
aryasaatvik Jun 13, 2026
141a7f1
feat(react): render plugin nav pages as sidebar tabs
aryasaatvik Jun 13, 2026
c80bde0
feat(plugin-service-tokens): add service-token alias plugin
aryasaatvik Jun 13, 2026
fa56e88
feat(host-cloudflare): alias Access service tokens to human subjects
aryasaatvik Jun 13, 2026
5ce4477
feat(plugin-service-tokens): capture machine name + acting-as identity
aryasaatvik Jun 14, 2026
382e73d
feat(host-cloudflare): set a service-token run actor + acts-as identity
aryasaatvik Jun 14, 2026
55ec1bb
fix(plugin-service-tokens): stop the machine-name input from collapsing
aryasaatvik Jun 15, 2026
a9790dc
style(service-tokens): format plugin + cf-access seam with oxfmt
aryasaatvik Jun 15, 2026
0eae72b
feat(execution-history): move run detail to R2, slim the D1 index (#24)
aryasaatvik Jun 15, 2026
1304189
feat(plugin-service-tokens): edit a machine name on an existing alias
aryasaatvik Jun 15, 2026
aa3c278
feat(execution-history): content-fit runs table columns + centered te…
aryasaatvik Jun 15, 2026
7efcd17
refactor(plugin-service-tokens): table layout for the alias list
aryasaatvik Jun 15, 2026
50d6e2a
feat(execution-history): render live machine names for run actors
aryasaatvik Jun 15, 2026
b0fa3a0
feat: semantic tools.search via a Cloudflare Vectorize plugin (#26)
aryasaatvik Jun 15, 2026
7747efc
feat(plugin-vectorize-search): facet chunking, hybrid RRF, and increm…
aryasaatvik Jun 16, 2026
6bd7a23
feat(plugin-vectorize-search): local eval harness with pluggable embe…
aryasaatvik Jun 16, 2026
6cb665a
refactor: drop the underscore prefix from unused parameters (#29)
aryasaatvik Jun 16, 2026
0a8fd7d
refactor(plugin-semantic-search): backend-agnostic rename + decoupled…
aryasaatvik Jun 16, 2026
d5ce1d9
test(host-selfhost): quarantine flaky concurrent-identity isolation t…
aryasaatvik Jun 16, 2026
723cf0f
fix(package): remove duplicate entry for 'effect' in dependencies and…
aryasaatvik Jun 16, 2026
c3e48e0
feat(plugin-semantic-search): D1-backed FTS5 lexical store + hybrid r…
aryasaatvik Jun 17, 2026
a8f624a
feat(plugin-semantic-search): operator Search console page + live sea…
aryasaatvik Jun 17, 2026
f1f0f5c
feat(plugin-semantic-search): paged reindex — reconcileToolCatalogPag…
aryasaatvik Jun 17, 2026
046b6a8
feat(sdk): cache TypeScript schema previews (#35)
aryasaatvik Jun 18, 2026
a2c1c6d
fix(cloudflare): use resumable MCP streams (#38)
aryasaatvik Jun 18, 2026
3162181
chore(cloudflare): improve MCP session observability (#39)
aryasaatvik Jun 18, 2026
a3a62fc
refactor(mcp): use streamable http for remote clients (#40)
aryasaatvik Jun 18, 2026
ef2cbfe
perf(sdk): cache tool schema views (#36)
aryasaatvik Jun 18, 2026
63a22f3
feat(host-cloudflare): serve MCP with Agents (#41)
aryasaatvik Jun 19, 2026
234cb8e
feat(plugin-semantic-search): add staged reindex pipeline (#37)
aryasaatvik Jun 19, 2026
b418fd9
feat(sdk): add tool schema manifest (#42)
aryasaatvik Jun 19, 2026
b9448be
perf(semantic-search): scan from tool manifests (#43)
aryasaatvik Jun 19, 2026
84ce77f
fix(semantic-search): reconstruct queued index work
aryasaatvik Jun 19, 2026
fed7605
perf(semantic-search): reduce queued index work (#44)
aryasaatvik Jun 19, 2026
ee65498
perf(semantic-search): batch index storage operations (#45)
aryasaatvik Jun 19, 2026
ae221f3
perf(storage): batch plugin storage upserts (#46)
aryasaatvik Jun 20, 2026
95e0724
fix(semantic-search): preserve maxTools across resume (#47)
aryasaatvik Jun 20, 2026
d1e35b0
fix(semantic-search): don't default the search prefix filter to the t…
aryasaatvik Jun 21, 2026
52d3876
perf(sdk): precompile tool-schema TypeScript during indexing (#49)
aryasaatvik Jun 21, 2026
81e65df
perf(sdk): cache tools.list by catalog + policy revision (#50)
aryasaatvik Jun 21, 2026
4bb027a
perf(web): virtualize long lists behind a shared windowing primitive …
aryasaatvik Jun 21, 2026
871c29a
perf(semantic-search): snapshot the tool manifest per run (KV-only sc…
aryasaatvik Jun 22, 2026
5963cc6
chore(sync): merge upstream main for review
aryasaatvik Jun 23, 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
13 changes: 13 additions & 0 deletions .changeset/execution-history-content-fit-table.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@executor-js/plugin-execution-history": patch
---

Rebuild the runs list as a real semantic `<table>` with content-fit columns.
Each column now sizes to the maximum width its rows need (browser
`table-layout: auto`), instead of fixed pixel widths — the sticky `<thead>` and
the rows share one column model so they stay aligned for free. Short / numeric /
badge columns (status, duration, tools, interaction, log) are centered; text
columns (started, trigger, actor, code) are left-aligned. The two columns that
can run long — `actor` and `code` — are width-capped and truncated (hover shows
the full value). Removes the fixed-width `COL_*` slot constants and the
`min-w` horizontal-scroll floor.
12 changes: 12 additions & 0 deletions .changeset/execution-history-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@executor-js/plugin-execution-history": minor
---

Add the `@executor-js/plugin-execution-history` plugin — an opt-in execution
history sink built on the ExecutionObserver foundation. It records every run
(plus its tool calls and interactions) into three owner-scoped pluginStorage
collections via a buffered-batch writer (no new tables, no migrations; works on
D1/libSQL/sqlite/postgres), exposes a `list`/`get`/`listToolCalls` read API over
HttpApi (`./api`'s `executionHistoryHttpPlugin`), and ships a Runs page UI
(`./client`) that mounts at `/plugins/executionHistory/`. The base `.` entry is
SDK-only and never loads `@executor-js/api` or React.
18 changes: 18 additions & 0 deletions .changeset/execution-history-r2-detail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
"@executor-js/plugin-execution-history": minor
---

Move per-run detail to an append-only R2 object and slim the D1 index. The
`runs` row now keeps only list/aggregate fields plus a bounded `codePreview` and
denormalized `logErrorCount`/`logWarnCount`, so the runs list renders entirely
from D1 with no per-row blob fetch. Full `code`, `resultJson`, `errorText`,
`logsJson`, `triggerMetaJson`, and the per-tool-call / per-interaction rows now
live in one immutable object per run in the plugin blob store (keyed
`run-detail/<executionId>`) — a code-only stub on `ExecutionStarted`, the full
detail on finish. The detail drawer reads it in a single request (`get`
flat-merges the R2 detail onto the slim run); the separate tool-calls endpoint
and `runToolCallsAtom` are removed, and the `toolCalls`/`interactions`
collections are gone.

Breaking: the runs list/detail response shapes change and past runs are cleared
(no backfill, no compatibility shim — the cutover wipe is authoritative).
15 changes: 15 additions & 0 deletions .changeset/execution-history-rich-list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@executor-js/plugin-execution-history": minor
---

Rework the runs list into a keyset-paginated, aggregate-aware read surface
backed by the storage JSON pushdown. The `list` endpoint now takes an opaque
keyset `cursor` (instead of offset), a sort field (`startedAt`/`durationMs`)
with direction, and a live-tail `after` floor, and returns `{ runs, nextCursor,
meta }`. The `meta` block — computed once per filter set on the first page —
carries status/trigger facet counts (each ignoring its own filter), interaction
counts, a stacked-by-status timeline with a server-chosen bucket width, total
and filtered row counts, and duration min/max plus P50–P99 percentiles. All
counts, buckets, percentiles, and pages are pushed to SQL rather than reducing
the whole collection in memory. Tool-path facets and full-text code search are
intentionally not included yet.
13 changes: 13 additions & 0 deletions .changeset/execution-history-runs-ui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@executor-js/plugin-execution-history": minor
---

Rebuild the runs page as an openstatus-style observability table on the keyset +
aggregate API. The page now has a faceted filter rail (status / trigger /
interaction / time range with live counts), a cmdk filter command palette, a
stacked-by-status timeline chart with drag-to-zoom, live tailing, keyset
infinite scroll, sortable columns, column visibility, keyboard shortcuts, and
the existing 4-tab detail drawer. List data flows through an Effect-atoms hook
(`useRunsList`) that accumulates cursor pages and polls the head for live mode;
the accumulation logic is a pure, unit-tested reducer. Adds `recharts` as an
optional peer dependency (provided by `@executor-js/react`).
13 changes: 13 additions & 0 deletions .changeset/execution-metrics-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@executor-js/plugin-execution-metrics": minor
---

Add the `@executor-js/plugin-execution-metrics` plugin — an opt-in metrics sink
built on the ExecutionObserver foundation. The base plugin drives Effect Metric
counters and an execution-duration histogram from the event stream; `./api`'s
`executionMetricsHttpPlugin` exposes them as an auth-gated `GET
/execution-metrics/metrics` Prometheus scrape for long-lived hosts; and
`./cloudflare`'s `createWaeMetricsObserver` writes Workers Analytics Engine data
points on the Cloudflare host (per-isolate Effect metrics being meaningless on a
Worker fleet). The base `.` entry never loads `@executor-js/api` or
`@cloudflare/workers-types`.
14 changes: 14 additions & 0 deletions .changeset/execution-observer-foundation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@executor-js/sdk": minor
"@executor-js/execution": minor
"@executor-js/api": minor
---

Add the execution-observer foundation. The execution engine now emits a typed
lifecycle stream (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`,
`InteractionStarted`/`Resolved`), plugins can subscribe via the new
`plugin.runtime.executionObserver` hook, and `makeExecutionStack` composes every
registered plugin's observer onto the engine. Behaviour is unchanged when no
plugin observes — this is the opt-in seam the execution-history and
execution-metrics plugins build on. Also exposes `Executor.owner` and enriches
the `mcp.execute` span with the run id and trigger.
16 changes: 16 additions & 0 deletions .changeset/fumadb-json-pushdown.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@executor-js/fumadb": minor
"@executor-js/sdk": minor
---

Push JSON-document aggregation and keyset pagination down to SQL. FumaDB's query
layer gains `jsonCount`, `jsonGroupCount`, `jsonTimeBuckets`, `jsonStats`
(min/max + continuous percentiles), and `jsonPage` (cursor pagination) over a
JSON document column, implemented natively for the memory and Drizzle
(SQLite/Postgres) adapters and failing loudly on adapters that don't support
them. Plugin storage exposes this as `collection.aggregate.{count,groupCount,
timeBuckets,stats}` and `collection.queryKeyset(...)`, translating a
collection's indexed-field `where` into JSON-path predicates while owner/tenant
scoping stays enforced by the storage policy. Aggregates and pages are computed
in the database instead of by fetching the whole collection and reducing in
memory.
10 changes: 10 additions & 0 deletions .changeset/semantic-search-manifest-snapshot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@executor-js/sdk": minor
"@executor-js/plugin-semantic-search": minor
---

Snapshot the tool manifest per reindex run instead of re-reading it from D1 on every scan page.

`createExecutor` now exposes its cache `KeyValueStore` on the executor instance as `executor.cache`, so plugins can reach durable cache storage (Cloudflare KV in production) without re-threading a binding — wrap it with `KeyValueStore.toSchemaStore` for typed entries, the same way the internal `tools.list` / schema-view caches do.

The semantic-search scan phase used to call `tools.manifest()` — a full `tool_schema_manifest` table read — once per partition page, so an unchanged catalog cost `O(N² / pageLimit)` cross-region reads. Now `create` reads the manifest once, partitions it, and writes one snapshot per partition to `executor.cache`; `scan` reads only its partition's snapshot (KV-only, with no D1 fallback on the hot path — a miss fails the message so the queue retries). Snapshots are deleted when the run completes. This collapses the scan's manifest reads from `O(N² / pageLimit)` to a single pass and cuts per-message memory from the whole manifest to one partition's slice.
14 changes: 14 additions & 0 deletions .changeset/semantic-search-tenant-namespace-prefix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@executor-js/plugin-semantic-search": patch
---

fix: don't default the operator search prefix filter to the tenant namespace

`executor.semanticSearch.search` (the operator `tools.search` surface) overloaded a
single `namespace` value as both the Vectorize tenant namespace (storage isolation)
and the optional integration/path-prefix filter. With no operator-supplied prefix it
defaulted the filter to the tenant namespace (e.g. `"default"`), so the provider's
`matchesNamespace` required every tool path to start with the tenant id and dropped
every result — search returned nothing for all queries despite a fully populated
index. The integration prefix is now applied only when explicitly provided; the
tenant namespace drives the store query alone and is still reported on the result page.
14 changes: 14 additions & 0 deletions .changeset/tools-list-revision-cache.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@executor-js/sdk": minor
---

Cache `tools.list` by a content-derived catalog revision. `produceConnectionTools` now
records a per-connection `toolset_revision` — a hash of the connection's manifest
`(path, index_fingerprint)` pairs — in `plugin_storage`, and `tools.list` keys a KV cache of
the DB-derived, policy-filtered list on the combined catalog revision plus a policy
revision (both read live, O(connections)/O(policies), not the full `tool` scan). Static tools
are unioned live and the `query` substring filter is applied post-cache, so a distinct query
reuses the same cached set. The cache stays warm through token rotation and unrelated writes
and invalidates exactly when a connection's tool set, a tool's schema, or a `tool_policy`
changes — including OpenAPI/MCP tool additions on refresh (a new manifest row) and
connection/integration removal.
15 changes: 15 additions & 0 deletions .changeset/tools-schema-precompile-typescript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@executor-js/sdk": minor
"@executor-js/plugin-semantic-search": patch
---

Always render the TypeScript preview in `executor.tools.schema` and warm it during
indexing. The `includeTypeScript` option (and the now-empty `ToolSchemaOptions` type) is
removed — the only caller that passed `false` was the reindex pipeline, which did so to
skip the CPU-heavy JSON-schema → TypeScript codegen. It now calls `tools.schema` plainly,
so every reindex pre-warms exactly the schema view the web UI reads on first open (the
codegen is content-addressed in KV), turning first tool-detail views into cache hits
instead of a cold compile. The embedding text is unchanged — the indexer only ever read
the raw schema facets, never the rendered TypeScript. Because `includeTypeScript` is
dropped from the schema-view cache key, existing cached entries are superseded on the next
reindex or view (regenerable derived data).
10 changes: 10 additions & 0 deletions .oxlintrc.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
"jsPlugins": [{ "name": "executor", "specifier": "./scripts/oxlint-plugin-executor.js" }],
"rules": {
"typescript/no-explicit-any": "error",
// Unused function parameters are allowed with their real names (no `_`
// prefix required) — keep a descriptive name for params retained for
// signature/interface reasons. Unused *variables* and imports are still
// flagged. Same for unused catch bindings. Destructuring-skip variables
// (e.g. `{ type: _type, ...rest }`) keep the `_` convention since they
// cannot be omitted structurally.
"no-unused-vars": [
"error",
{ "args": "none", "caughtErrors": "none", "varsIgnorePattern": "^_" },
],
"executor/no-vitest-import": "error",
"executor/no-conditional-tests": "error",
"executor/no-double-cast": "error",
Expand Down
3 changes: 2 additions & 1 deletion apps/cloud/src/api/protected-api-key-auth.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const stubApiKeys = Layer.succeed(ApiKeyService)({
const stubWorkOS = Layer.succeed(
WorkOSClient,
new Proxy({} as WorkOSClientService, {
get: (_target, prop) => {
get: (target, prop) => {
if (prop === "listUserMemberships") {
return (userId: string) =>
Effect.succeed({
Expand Down Expand Up @@ -87,6 +87,7 @@ describe("protected API key auth", () => {
accountId: "user_123",
organizationId: "org_123",
organizationName: "Org org_123",
organizationSlug: "org-slug-org_123",
email: "",
name: null,
avatarUrl: null,
Expand Down
1 change: 1 addition & 0 deletions apps/cloud/src/api/protected-jwt-auth.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ describe("protected JWT (device-login) auth", () => {
accountId: "user_123",
organizationId: "org_123",
organizationName: "Org org_123",
organizationSlug: "org-slug-org_123",
email: "",
name: null,
avatarUrl: null,
Expand Down
2 changes: 1 addition & 1 deletion apps/cloud/src/auth/api-keys.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const stubWorkOS = (overrides: Partial<WorkOSClientService>) =>
Layer.succeed(
WorkOSClient,
new Proxy({} as WorkOSClientService, {
get: (_target, prop) => {
get: (target, prop) => {
if (prop in overrides) return overrides[prop as keyof WorkOSClientService];
return () => Effect.die(`unexpected WorkOSClient.${String(prop)} call`);
},
Expand Down
20 changes: 14 additions & 6 deletions apps/cloud/src/auth/middleware-live.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
import { Effect, Layer, Redacted } from "effect";
import { HttpServerResponse } from "effect/unstable/http";

import { AuthContext, NoOrganization, Unauthorized } from "@executor-js/api/server";
import {
AuthContext,
authContextFromPrincipal,
NoOrganization,
Unauthorized,
} from "@executor-js/api/server";

import {
OrgAuth,
Expand Down Expand Up @@ -93,17 +98,20 @@ export const OrgAuthLive = Layer.effect(
// (org-settings → domain verification) is niche; URL-scoping it would
// mean converting this to an HttpRouter middleware — deferred.
const session = sessionFromSealed(result, Redacted.value(credential));
const auth = {
// Wrap the WorkOS session into a neutral `Principal` and let
// `authContextFromPrincipal` derive everything (incl. the run actor),
// so this path never re-implements the actor/label logic. `roles` is
// empty (the WorkOS control plane doesn't resolve them here; no cloud
// handler reads them) and `organizationName` is unused by AuthContext.
const auth = authContextFromPrincipal({
accountId: session.accountId,
organizationId: result.organizationId,
organizationName: "",
email: session.email,
name: session.name,
avatarUrl: session.avatarUrl,
// The unified `AuthContext` carries roles; cloud's WorkOS control
// plane does not resolve them here, so pass an empty list (no cloud
// handler reads roles today).
roles: [],
};
});

return yield* Effect.provideService(httpEffect, AuthContext, auth);
}),
Expand Down
2 changes: 1 addition & 1 deletion apps/cloud/src/auth/org-selector-auth.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const stubApiKeys = Layer.succeed(ApiKeyService)({
const stubWorkOS = Layer.succeed(
WorkOSClient,
new Proxy({} as WorkOSClientService, {
get: (_t, prop) => {
get: (target, prop) => {
if (prop === "authenticateRequest") {
return () =>
Effect.succeed({ userId: MEMBER, email: "u@e2e.test", organizationId: SESSION_ORG });
Expand Down
6 changes: 6 additions & 0 deletions apps/cloud/src/db/db.schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,14 @@ describe("combinedSchema", () => {
provider: "postgresql",
});
const schemaTables = drizzleTableColumns(combinedSchema);
const missingTables: string[] = [];
const missingColumns: string[] = [];

for (const table of Object.values(fumaDbInternals(fuma.db).internal.tables)) {
if (schemaTables[table.names.drizzle] === undefined) {
missingTables.push(table.names.drizzle);
continue;
}
const drizzleTable = drizzleTableColumns(schemaTables[table.names.drizzle]);
for (const column of Object.values(table.columns)) {
if (drizzleTable[column.names.drizzle] === undefined) {
Expand All @@ -119,6 +124,7 @@ describe("combinedSchema", () => {
}
}

expect(missingTables).toEqual([]);
expect(missingColumns).toEqual([]);
}),
),
Expand Down
38 changes: 38 additions & 0 deletions apps/cloud/src/db/executor-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,44 @@ export const definition = pgTable(
],
);

export const tool_schema_manifest = pgTable(
"tool_schema_manifest",
{
integration: varchar("integration", { length: 255 }).notNull(),
connection: varchar("connection", { length: 255 }).notNull(),
plugin_id: text("plugin_id").notNull(),
name: varchar("name", { length: 255 }).notNull(),
path: varchar("path", { length: 255 }).notNull(),
description: text("description").notNull(),
descriptor_hash: text("descriptor_hash").notNull(),
input_schema_hash: text("input_schema_hash").notNull(),
output_schema_hash: text("output_schema_hash").notNull(),
definition_set_hash: text("definition_set_hash").notNull(),
index_fingerprint: text("index_fingerprint").notNull(),
fingerprint_version: text("fingerprint_version").notNull(),
source_revision: text("source_revision"),
created_at: timestamp("created_at").notNull(),
updated_at: timestamp("updated_at").notNull(),
row_id: varchar("row_id", { length: 255 })
.primaryKey()
.notNull()
.$defaultFn(() => createId()),
tenant: varchar("tenant", { length: 255 }).notNull(),
owner: varchar("owner", { length: 255 }).notNull(),
subject: varchar("subject", { length: 255 }).notNull(),
},
(table) => [
uniqueIndex("tool_schema_manifest_uidx").on(
table.tenant,
table.owner,
table.subject,
table.integration,
table.connection,
table.name,
),
],
);

export const tool_policy = pgTable(
"tool_policy",
{
Expand Down
4 changes: 2 additions & 2 deletions apps/cloud/src/engine/execution-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export const withExecutionUsageTracking = <E extends Cause.YieldableError>(
engine
.execute(code, options)
.pipe(Effect.tap(() => Effect.sync(() => trackUsage(organizationId)))),
executeWithPause: (code) =>
executeWithPause: (code, options) =>
engine
.executeWithPause(code)
.executeWithPause(code, options)
.pipe(Effect.tap(() => Effect.sync(() => trackUsage(organizationId)))),
// resume doesn't count as usage
resume: (executionId, response) => engine.resume(executionId, response),
Expand Down
6 changes: 4 additions & 2 deletions apps/cloud/src/org/handlers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const stubWorkOS = (overrides: StubOverrides = {}) =>
Layer.succeed(
WorkOSClient,
new Proxy({} as WorkOSClientService, {
get: (_target, prop) => {
get: (target, prop) => {
if (typeof prop === "string" && prop in overrides) {
return overrides[prop as keyof StubOverrides];
}
Expand All @@ -53,6 +53,7 @@ const adminAuth = {
name: "Admin",
avatarUrl: null,
roles: [],
actor: { kind: "user", id: "user_admin", label: "Admin" },
};

const memberAuth = {
Expand All @@ -62,6 +63,7 @@ const memberAuth = {
name: "Member",
avatarUrl: null,
roles: [],
actor: { kind: "user", id: "user_member", label: "Member" },
};

const provide = (auth: typeof adminAuth, workosOverrides: StubOverrides = {}) =>
Expand All @@ -78,7 +80,7 @@ const requireAdmin = Effect.gen(function* () {
});

const withCurrentMembership: StubOverrides = {
getUserOrgMembership: (_organizationId: string, userId: string) =>
getUserOrgMembership: (organizationId: string, userId: string) =>
Effect.succeed(
userId === "user_admin"
? { id: "mem_admin", userId, status: "active", role: { slug: "admin" } }
Expand Down
Loading
Loading