@rudderhq/agent-runtime-opencode-local 0.7.2-canary.0 → 0.7.3
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/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/models.d.ts.map +1 -1
- package/dist/server/models.js +86 -4
- package/dist/server/models.js.map +1 -1
- package/dist/server/models.test.js +31 -0
- package/dist/server/models.test.js.map +1 -1
- package/package.json +2 -2
- package/skills/app-builder/SKILL.md +39 -9
- package/skills/app-builder/assets/scaffold/app/globals.css +109 -16
- package/skills/app-builder/assets/scaffold/components/contacts-workspace.tsx +176 -152
- package/skills/app-builder/assets/scaffold/components/ui/alert.tsx +12 -0
- package/skills/app-builder/assets/scaffold/components/ui/badge.tsx +27 -0
- package/skills/app-builder/assets/scaffold/components/ui/button.tsx +9 -7
- package/skills/app-builder/assets/scaffold/components/ui/card.tsx +15 -3
- package/skills/app-builder/assets/scaffold/components/ui/empty.tsx +18 -0
- package/skills/app-builder/assets/scaffold/components/ui/field.tsx +23 -0
- package/skills/app-builder/assets/scaffold/components/ui/input.tsx +1 -1
- package/skills/app-builder/assets/scaffold/components/ui/label.tsx +1 -1
- package/skills/app-builder/assets/scaffold/components/ui/separator.tsx +6 -0
- package/skills/app-builder/assets/scaffold/components/ui/skeleton.tsx +6 -0
- package/skills/app-builder/assets/scaffold/components/ui/table.tsx +30 -0
- package/skills/app-builder/assets/scaffold/components.json +20 -0
- package/skills/app-builder/assets/scaffold/next-env.d.ts +1 -1
- package/skills/app-builder/assets/scaffold/next.config.ts +19 -0
- package/skills/app-builder/assets/scaffold/package.json +2 -1
- package/skills/app-builder/assets/scaffold/rudder.app.json +1 -1
- package/skills/app-builder/assets/scaffold/rudder.ui.json +13 -0
- package/skills/app-builder/assets/scaffold/scripts/validate-rudder-ui.mjs +50 -0
- package/skills/app-builder/assets/scaffold/tests/e2e/app.spec.ts +35 -1
- package/skills/app-builder/evals/evals.json +2 -1
- package/skills/app-builder/references/design-guidelines.md +19 -2
- package/skills/app-builder/references/rudder-ui-preset.md +73 -0
- package/skills/app-builder/references/scaffold-contract.md +12 -0
- package/skills/app-builder/references/verification.md +6 -0
- package/skills/app-builder/scripts/report-build-status.mjs +83 -0
- package/skills/browser/SKILL.md +11 -4
- package/skills/browser/agents/openai.yaml +2 -2
- package/skills/browser/evals/trigger-evals.json +22 -0
- package/skills/rudder-docs/SKILL.md +2 -2
- package/skills/rudder-docs/evals/retrieval-authority-evals.json +40 -0
- package/skills/rudder-docs/evals/trigger-evals.json +2 -2
- package/skills/rudder-docs/references/api-reference.md +0 -2
- package/skills/rudder-docs/references/plugin-authoring.md +38 -114
- package/skills/rudder-docs/references/source-map.md +2 -0
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
import type { NextConfig } from "next";
|
|
2
2
|
|
|
3
3
|
const nextConfig: NextConfig = {
|
|
4
|
+
devIndicators: false,
|
|
4
5
|
output: "standalone",
|
|
5
6
|
poweredByHeader: false,
|
|
7
|
+
turbopack: {
|
|
8
|
+
root: process.cwd(),
|
|
9
|
+
},
|
|
10
|
+
webpack(config, { isServer }) {
|
|
11
|
+
if (isServer) {
|
|
12
|
+
config.externals.push((
|
|
13
|
+
{ request }: { request?: string },
|
|
14
|
+
callback: (error?: Error | null, result?: string) => void,
|
|
15
|
+
) => {
|
|
16
|
+
if (request?.startsWith("node:")) {
|
|
17
|
+
callback(null, `commonjs ${request}`);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
callback();
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return config;
|
|
24
|
+
},
|
|
6
25
|
};
|
|
7
26
|
|
|
8
27
|
export default nextConfig;
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"db:migrate": "tsx scripts/migrate.ts",
|
|
18
18
|
"db:seed": "tsx scripts/seed.ts",
|
|
19
19
|
"data:snapshot": "tsx scripts/snapshot.ts",
|
|
20
|
-
"
|
|
20
|
+
"ui:check": "node scripts/validate-rudder-ui.mjs",
|
|
21
|
+
"verify": "pnpm ui:check && tsc --noEmit && vitest run && next build",
|
|
21
22
|
"predev": "tsx scripts/migrate.ts && tsx scripts/seed.ts"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { access, readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
const root = process.cwd();
|
|
5
|
+
const requiredFiles = [
|
|
6
|
+
"components.json",
|
|
7
|
+
"app/globals.css",
|
|
8
|
+
"components/ui/button.tsx",
|
|
9
|
+
"components/ui/field.tsx",
|
|
10
|
+
"components/ui/table.tsx",
|
|
11
|
+
"components/ui/empty.tsx",
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
function fail(message) {
|
|
15
|
+
console.error(`Rudder UI preset invalid: ${message}`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let preset;
|
|
20
|
+
try {
|
|
21
|
+
preset = JSON.parse(await readFile(path.join(root, "rudder.ui.json"), "utf8"));
|
|
22
|
+
} catch {
|
|
23
|
+
fail("rudder.ui.json is missing or invalid JSON");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (preset?.schemaVersion !== 1 || preset?.preset !== "rudder") {
|
|
27
|
+
fail("unsupported preset identity");
|
|
28
|
+
}
|
|
29
|
+
if (!Number.isInteger(preset?.revision) || preset.revision < 1) {
|
|
30
|
+
fail("revision must be a positive integer");
|
|
31
|
+
}
|
|
32
|
+
if (preset?.sourceOwnership !== "app") {
|
|
33
|
+
fail("generated Apps must own their component source");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
for (const relativePath of requiredFiles) {
|
|
37
|
+
try {
|
|
38
|
+
await access(path.join(root, relativePath));
|
|
39
|
+
} catch {
|
|
40
|
+
fail(`required file is missing: ${relativePath}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const css = await readFile(path.join(root, "app/globals.css"), "utf8");
|
|
45
|
+
for (const token of ["--background", "--foreground", "--primary", "--destructive", "--border", "--ring", "--radius"]) {
|
|
46
|
+
if (!css.includes(`${token}:`)) fail(`semantic token is missing: ${token}`);
|
|
47
|
+
}
|
|
48
|
+
if (!css.includes("@theme inline")) fail("Tailwind semantic token mapping is missing");
|
|
49
|
+
|
|
50
|
+
console.log(`Rudder UI preset ${preset.revision}: ok`);
|
|
@@ -4,7 +4,7 @@ test("creates a contact and keeps it after reload", async ({ page }) => {
|
|
|
4
4
|
const suffix = crypto.randomUUID();
|
|
5
5
|
const name = `Avery ${suffix.slice(0, 8)}`;
|
|
6
6
|
await page.goto("/");
|
|
7
|
-
await expect(page.getByRole("heading", { name: "
|
|
7
|
+
await expect(page.getByRole("heading", { name: "Contacts", exact: true })).toBeVisible();
|
|
8
8
|
await page.getByLabel("Name").fill(name);
|
|
9
9
|
await page.getByLabel("Email").fill(`${suffix}@example.test`);
|
|
10
10
|
await page.getByLabel("Company").fill("Acme");
|
|
@@ -14,6 +14,40 @@ test("creates a contact and keeps it after reload", async ({ page }) => {
|
|
|
14
14
|
await expect(page.getByText(name)).toBeVisible();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
+
test("ships the Rudder UI preset in system light and dark modes", async ({ browser }) => {
|
|
18
|
+
const lightPage = await browser.newPage({ colorScheme: "light" });
|
|
19
|
+
await lightPage.goto("/");
|
|
20
|
+
await expect(lightPage.getByText("Pipeline Desk")).toBeVisible();
|
|
21
|
+
const lightStyle = await lightPage.evaluate(() => {
|
|
22
|
+
const style = getComputedStyle(document.documentElement);
|
|
23
|
+
return {
|
|
24
|
+
background: getComputedStyle(document.body).backgroundColor,
|
|
25
|
+
radius: style.getPropertyValue("--radius"),
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
expect(Number.parseFloat(lightStyle.radius)).toBe(0.375);
|
|
29
|
+
|
|
30
|
+
const darkPage = await browser.newPage({ colorScheme: "dark" });
|
|
31
|
+
await darkPage.goto("/");
|
|
32
|
+
const darkBackground = await darkPage.evaluate(() => (
|
|
33
|
+
getComputedStyle(document.body).backgroundColor
|
|
34
|
+
));
|
|
35
|
+
expect(darkBackground).not.toBe(lightStyle.background);
|
|
36
|
+
await lightPage.close();
|
|
37
|
+
await darkPage.close();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("keeps the primary workflow usable at 390px", async ({ page }) => {
|
|
41
|
+
await page.setViewportSize({ width: 390, height: 844 });
|
|
42
|
+
await page.goto("/");
|
|
43
|
+
await expect(page.getByRole("heading", { name: "Contacts", exact: true })).toBeVisible();
|
|
44
|
+
await expect(page.getByRole("heading", { name: "Add contact" })).toBeVisible();
|
|
45
|
+
await expect(page.getByLabel("Search contacts")).toBeVisible();
|
|
46
|
+
await expect(page.getByRole("button", { name: "Delete Maya Chen" })).toBeVisible();
|
|
47
|
+
await expect(page.getByText("Northwind").first()).toBeVisible();
|
|
48
|
+
await expect(page.locator("nextjs-portal")).toBeHidden();
|
|
49
|
+
});
|
|
50
|
+
|
|
17
51
|
test("shows the empty-search state", async ({ page }) => {
|
|
18
52
|
await page.goto("/");
|
|
19
53
|
await page.getByLabel("Search contacts").fill("no matching record");
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"assertions": [
|
|
10
10
|
"Does not ask the user to choose a framework, database, package manager, or process topology.",
|
|
11
11
|
"Uses the maintained App Builder scaffold and SQLite persistence.",
|
|
12
|
+
"Uses the versioned Rudder UI preset and its semantic shadcn primitives instead of inventing a generic dashboard theme.",
|
|
12
13
|
"Does not ask for or place email credential values in Chat or source.",
|
|
13
14
|
"Includes the primary contact workflow plus import, persistence, and a production-shaped edge case in verification."
|
|
14
15
|
]
|
|
@@ -32,7 +33,7 @@
|
|
|
32
33
|
"files": [],
|
|
33
34
|
"assertions": [
|
|
34
35
|
"Does not inspect or mutate real customer records merely to design the table.",
|
|
35
|
-
"Uses the existing
|
|
36
|
+
"Uses the existing Rudder UI preset components and semantic tokens, preserves readable density, and avoids decorative dashboard clutter.",
|
|
36
37
|
"Verifies the table at desktop width and a 390px viewport.",
|
|
37
38
|
"Captures rendered screenshot evidence and checks an empty or error state."
|
|
38
39
|
]
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Design for the user's actual workflow rather than for a technology demo.
|
|
4
4
|
|
|
5
|
+
For new maintained Apps, begin with the scaffold's versioned Rudder UI preset.
|
|
6
|
+
Do not replace its semantic tokens with a generic shadcn preset, a one-off
|
|
7
|
+
palette, or copied host application CSS. The generated App owns its component
|
|
8
|
+
source and must remain independently runnable outside Rudder.
|
|
9
|
+
|
|
5
10
|
- Put the primary action and current work state above decorative summaries.
|
|
6
11
|
- Use tables for operational lists, with search, meaningful filters, sorting,
|
|
7
12
|
pagination when needed, empty states, and clear row actions.
|
|
@@ -11,10 +16,22 @@ Design for the user's actual workflow rather than for a technology demo.
|
|
|
11
16
|
navigation, not both.
|
|
12
17
|
- Prefer readable density for CRM and marketing data. Avoid oversized KPI cards,
|
|
13
18
|
excessive gradients, glass panels, and placeholder charts.
|
|
14
|
-
- Use the scaffold's
|
|
15
|
-
one-off styling.
|
|
19
|
+
- Use the scaffold's shadcn primitives and semantic theme tokens before adding
|
|
20
|
+
new components or one-off styling. Compose `Button`, `Input`, `Field`,
|
|
21
|
+
`Table`, `Badge`, `Alert`, `Empty`, `Skeleton`, and `Separator` instead of
|
|
22
|
+
recreating those patterns with styled `div` elements.
|
|
23
|
+
- Keep Rudder's default visual character: calm, dense, operational, quiet, and
|
|
24
|
+
precise. Use compact radii, low-contrast borders, restrained elevation, one
|
|
25
|
+
clear primary action, and color for state or emphasis rather than decoration.
|
|
26
|
+
- Use semantic utilities such as `bg-background`, `text-foreground`,
|
|
27
|
+
`bg-muted`, and `text-destructive`. Do not hardcode product colors in
|
|
28
|
+
workflow components or add component-local dark-mode colors.
|
|
29
|
+
- Treat the preset as a starting system, not a brand lock. When the brief calls
|
|
30
|
+
for a distinct brand, keep the component structure, density, accessibility,
|
|
31
|
+
and state behavior while changing the named token layer deliberately.
|
|
16
32
|
- Support keyboard use, visible focus, semantic headings, accessible names, and
|
|
17
33
|
error text that does not rely on color.
|
|
18
34
|
- Verify at desktop width and at 390px mobile width unless the brief excludes
|
|
19
35
|
mobile.
|
|
20
36
|
- Show loading, empty, error, populated, and destructive-operation states.
|
|
37
|
+
- Run `pnpm ui:check` before final verification for new maintained Apps.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Rudder UI Preset
|
|
2
|
+
|
|
3
|
+
The maintained scaffold includes a versioned, source-owned shadcn preset for
|
|
4
|
+
building local operator tools that feel immediately at home in Rudder.
|
|
5
|
+
|
|
6
|
+
## Source Of Truth
|
|
7
|
+
|
|
8
|
+
- `rudder.ui.json` identifies the preset and revision.
|
|
9
|
+
- `components.json` makes the generated project a conventional shadcn project.
|
|
10
|
+
- `app/globals.css` owns semantic color, radius, typography, and light/dark
|
|
11
|
+
tokens.
|
|
12
|
+
- `components/ui/` owns copied component source. Generated Apps do not import
|
|
13
|
+
components or CSS from the Rudder repository at runtime.
|
|
14
|
+
- `scripts/validate-rudder-ui.mjs` checks that the preset contract remains
|
|
15
|
+
present before handoff.
|
|
16
|
+
|
|
17
|
+
For new Apps, use this preset without asking the user to select a shadcn style,
|
|
18
|
+
base palette, accent, radius, or component library. The default is Rudder's
|
|
19
|
+
spacious-but-compact `luma` character, neutral surfaces, emerald action color,
|
|
20
|
+
and system light/dark mode.
|
|
21
|
+
|
|
22
|
+
## Composition Rules
|
|
23
|
+
|
|
24
|
+
1. Start with the shipped primitives. Extend them with variants when the same
|
|
25
|
+
need recurs; do not restyle each call site.
|
|
26
|
+
2. Use semantic Tailwind utilities rather than raw color utilities. New named
|
|
27
|
+
product colors belong in the token layer.
|
|
28
|
+
3. Keep normal controls between 32 and 36 pixels high, use compact radii, and
|
|
29
|
+
reserve pills for true circular or exceptional status affordances.
|
|
30
|
+
4. Bind native `button`, `input`, `select`, and `textarea` text to the inherited
|
|
31
|
+
semantic foreground color so system dark mode cannot reintroduce browser-UA
|
|
32
|
+
contrast regressions.
|
|
33
|
+
5. Use one primary panel or table region. Cards group independent objects or
|
|
34
|
+
actions; they are not wrappers for every section.
|
|
35
|
+
6. Operational lists require search or filtering when useful, readable row
|
|
36
|
+
actions, empty/loading/error states, and horizontal containment on narrow
|
|
37
|
+
screens.
|
|
38
|
+
7. Use Lucide icons for familiar actions. Icon-only controls need accessible
|
|
39
|
+
labels; icons inside buttons inherit their size from `Button`.
|
|
40
|
+
8. Preserve keyboard focus, semantic headings, persistent labels, inline
|
|
41
|
+
validation, and destructive confirmation.
|
|
42
|
+
|
|
43
|
+
## Appearance Boundary
|
|
44
|
+
|
|
45
|
+
The preset is copied into the App as a stable creation-time baseline. It does
|
|
46
|
+
not read Rudder's browser-local Appearance preferences or import host CSS at
|
|
47
|
+
runtime. This keeps the App portable and prevents a later Rudder theme change
|
|
48
|
+
from silently changing an independently branded product.
|
|
49
|
+
|
|
50
|
+
An App may add a documented host-theme bridge later, but light/dark following
|
|
51
|
+
must be optional and the standalone URL must still render correctly. Changing
|
|
52
|
+
that boundary is product behavior, not an incidental styling edit.
|
|
53
|
+
|
|
54
|
+
## Existing Projects
|
|
55
|
+
|
|
56
|
+
Do not install or overwrite the preset in an existing project by default.
|
|
57
|
+
Inspect its framework, component library, tokens, and brand first. If the user
|
|
58
|
+
explicitly asks to align it with Rudder, preserve application behavior and
|
|
59
|
+
choose a bounded migration:
|
|
60
|
+
|
|
61
|
+
- token-only alignment when components are already coherent;
|
|
62
|
+
- primitive-by-primitive alignment when a source-owned component system exists;
|
|
63
|
+
- full preset adoption only when the user accepts the wider visual change.
|
|
64
|
+
|
|
65
|
+
Never run a shadcn overwrite command over locally modified components without
|
|
66
|
+
explicit approval and a reviewed diff.
|
|
67
|
+
|
|
68
|
+
## Verification
|
|
69
|
+
|
|
70
|
+
Run `pnpm ui:check`, typecheck, tests, build, and the App's Playwright suite.
|
|
71
|
+
In Browser, inspect the primary workflow, loading or empty state, inline error,
|
|
72
|
+
destructive action, desktop layout, 390px layout, and light/dark contrast.
|
|
73
|
+
Capture the useful populated state rather than a decorative empty dashboard.
|
|
@@ -25,6 +25,8 @@ definition through **Apps + > Add local web project** before anything runs.
|
|
|
25
25
|
|
|
26
26
|
- Next.js App Router, React, and TypeScript
|
|
27
27
|
- Tailwind CSS with shadcn-style component source owned by the project
|
|
28
|
+
- a versioned Rudder UI preset with semantic light/dark tokens and compact
|
|
29
|
+
operator-tool primitives
|
|
28
30
|
- SQLite with Drizzle ORM
|
|
29
31
|
- Zod at API, import, and form boundaries
|
|
30
32
|
- Vitest for unit tests and Playwright for browser tests
|
|
@@ -36,6 +38,8 @@ implementation detail and must not become a user decision.
|
|
|
36
38
|
## Required Files And Behaviors
|
|
37
39
|
|
|
38
40
|
- `rudder.app.json` uses schema version 1 and a maintained template revision.
|
|
41
|
+
- `rudder.ui.json` identifies the source-owned Rudder UI preset revision;
|
|
42
|
+
`components.json` keeps the project compatible with the normal shadcn CLI.
|
|
39
43
|
- `/api/__rudder/health` returns readiness only after the app can open its
|
|
40
44
|
selected database.
|
|
41
45
|
- `RUDDER_APP_DATA_MODE=development|production` selects the database without
|
|
@@ -64,6 +68,12 @@ manifest.
|
|
|
64
68
|
## Commands
|
|
65
69
|
|
|
66
70
|
- `pnpm dev`: migrate the development database, then run loopback development.
|
|
71
|
+
- On Windows, Rudder's managed preview may select Next.js webpack while keeping
|
|
72
|
+
`node:*` built-ins external to the server bundle. This preserves the short
|
|
73
|
+
managed dependency layout required by native package executables without
|
|
74
|
+
changing the App's website output. The managed runtime supplies the same
|
|
75
|
+
compatibility to existing revision-1 Apps without rewriting their
|
|
76
|
+
`next.config.ts`, `next-env.d.ts`, or other App-owned source files.
|
|
67
77
|
- `pnpm typecheck`: TypeScript validation.
|
|
68
78
|
- `pnpm test`: unit and API-contract tests.
|
|
69
79
|
- `pnpm build`: production build.
|
|
@@ -73,5 +83,7 @@ manifest.
|
|
|
73
83
|
- `pnpm data:snapshot`: copy the selected SQLite database to `data/snapshots/`
|
|
74
84
|
using SQLite's backup API.
|
|
75
85
|
- `pnpm verify`: typecheck, tests, and build.
|
|
86
|
+
- `pnpm ui:check`: validate the maintained Rudder UI preset files and semantic
|
|
87
|
+
token contract.
|
|
76
88
|
|
|
77
89
|
Formal app start must not silently migrate real data. Promotion owns that step.
|
|
@@ -18,6 +18,12 @@ substitute a shell HTTP response for UI acceptance.
|
|
|
18
18
|
8. Capture current screenshots of the useful final state.
|
|
19
19
|
9. Materialize screenshots in Chat, Run, or Library evidence.
|
|
20
20
|
|
|
21
|
+
Only after all required checks pass may the Agent report
|
|
22
|
+
`verified_source_ready` for the originating App. That report is not a prose
|
|
23
|
+
claim: it is a run-scoped handoff that causes Desktop to repeat its maintained
|
|
24
|
+
checks, start the attested loopback process, and open the App for the user.
|
|
25
|
+
Questions, partial results, and blockers must never emit the handoff.
|
|
26
|
+
|
|
21
27
|
Close temporary run-owned tabs after verification. Never use the user's
|
|
22
28
|
persistent app view as an Agent test fixture when that could mutate formal
|
|
23
29
|
data.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const STATUS = process.argv[2];
|
|
4
|
+
const APP_ID = process.argv[3];
|
|
5
|
+
const ALLOWED_STATUSES = new Set(["building", "verified_source_ready", "failed"]);
|
|
6
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
7
|
+
|
|
8
|
+
if (!ALLOWED_STATUSES.has(STATUS) || !UUID_PATTERN.test(APP_ID ?? "")) {
|
|
9
|
+
console.error("Usage: report-build-status.mjs <building|verified_source_ready|failed> <app-id>");
|
|
10
|
+
process.exit(2);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const apiUrl = process.env.RUDDER_API_URL?.trim();
|
|
14
|
+
const apiKey = process.env.RUDDER_API_KEY?.trim();
|
|
15
|
+
const orgId = process.env.RUDDER_ORG_ID?.trim();
|
|
16
|
+
const runId = process.env.RUDDER_RUN_ID?.trim();
|
|
17
|
+
if (!apiUrl || !apiKey || !orgId || !runId) {
|
|
18
|
+
console.error("Rudder run context is unavailable; do not report a completed App handoff.");
|
|
19
|
+
process.exit(2);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const base = apiUrl.replace(/\/+$/u, "");
|
|
23
|
+
const apiBase = new URL(base).pathname.replace(/\/+$/u, "").endsWith("/api")
|
|
24
|
+
? base
|
|
25
|
+
: `${base}/api`;
|
|
26
|
+
const endpoint = `${apiBase}/app-builder/${encodeURIComponent(APP_ID)}/build?orgId=${encodeURIComponent(orgId)}`;
|
|
27
|
+
const headers = {
|
|
28
|
+
authorization: `Bearer ${apiKey}`,
|
|
29
|
+
"content-type": "application/json",
|
|
30
|
+
};
|
|
31
|
+
const currentResponse = await fetch(
|
|
32
|
+
`${apiBase}/orgs/${encodeURIComponent(orgId)}/app-builder`,
|
|
33
|
+
{ headers },
|
|
34
|
+
);
|
|
35
|
+
if (!currentResponse.ok) {
|
|
36
|
+
console.error(`Rudder could not read the App handoff state (${currentResponse.status}).`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
const current = (await currentResponse.json()).find((app) => app.id === APP_ID);
|
|
40
|
+
if (!current) {
|
|
41
|
+
console.error("Rudder App handoff identity was not found in this organization.");
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
const duplicateRunId = STATUS === "verified_source_ready"
|
|
45
|
+
? current.latestVerificationRunId
|
|
46
|
+
: current.latestBuildRunId;
|
|
47
|
+
if (current.buildStatus === STATUS && duplicateRunId === runId) {
|
|
48
|
+
console.log(`App Builder status: ${current.buildStatus}`);
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
const allowedCurrentStatuses = STATUS === "building"
|
|
52
|
+
? new Set(["preparing", "ready", "launch_failed", "failed"])
|
|
53
|
+
: STATUS === "verified_source_ready"
|
|
54
|
+
? new Set(["building"])
|
|
55
|
+
: new Set(["preparing", "building"]);
|
|
56
|
+
if (!allowedCurrentStatuses.has(current.buildStatus)) {
|
|
57
|
+
console.error(
|
|
58
|
+
`Rudder rejected the stale App handoff transition ${current.buildStatus} -> ${STATUS}.`,
|
|
59
|
+
);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
const response = await fetch(
|
|
63
|
+
endpoint,
|
|
64
|
+
{
|
|
65
|
+
method: "PATCH",
|
|
66
|
+
headers,
|
|
67
|
+
body: JSON.stringify({
|
|
68
|
+
status: STATUS,
|
|
69
|
+
expectedStatus: current.buildStatus,
|
|
70
|
+
runId,
|
|
71
|
+
runKind: STATUS === "verified_source_ready" ? "verification" : "build",
|
|
72
|
+
}),
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
const detail = await response.text();
|
|
78
|
+
console.error(`Rudder rejected the App handoff (${response.status}): ${detail.slice(0, 500)}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const app = await response.json();
|
|
83
|
+
console.log(`App Builder status: ${app.buildStatus}`);
|
package/skills/browser/SKILL.md
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: browser
|
|
3
|
-
description: "Control Rudder's built-in Browser through the separate run-scoped rudder-browser MCP. Use for opening or showing pages, inspecting visible or interactive state, navigating, clicking, typing,
|
|
3
|
+
description: "Control Rudder's built-in Browser through the separate run-scoped rudder-browser MCP, but invoke this skill only when the user explicitly mentions or selects Rudder's built-in Browser, Rudder Browser, or $browser. Use it then for opening or showing pages, inspecting visible or interactive state, navigating, clicking, typing, localhost testing, responsive checks, screenshots, dialogs, downloads, uploads, exports, console logs, clipboard, page assets, or listing tabs already open in Rudder's built-in Browser. Do not invoke it for generic web browsing, URL visits, web research, localhost testing, screenshots, or page interaction when the user has not explicitly chosen Rudder's built-in Browser."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Browser
|
|
7
7
|
|
|
8
|
-
Use
|
|
9
|
-
|
|
10
|
-
Browser
|
|
8
|
+
Use Rudder's built-in Browser only when the user explicitly names or selects
|
|
9
|
+
that surface, for example by saying `Rudder Browser`, `Rudder's built-in
|
|
10
|
+
Browser`, or `$browser`, or by referring to a page or tab already open there.
|
|
11
|
+
The request must identify the Rudder Browser as the intended surface; a generic
|
|
12
|
+
request to browse the web, visit a URL, research a site, test localhost, take a
|
|
13
|
+
screenshot, or interact with a page is not enough to invoke this skill.
|
|
14
|
+
|
|
15
|
+
When explicitly selected, the Browser may share signed-in website state from
|
|
16
|
+
the local Rudder Browser profile. If the user does not explicitly select it,
|
|
17
|
+
do not open, inspect, or interact with Rudder's Browser on the skill's behalf.
|
|
11
18
|
|
|
12
19
|
The Browser is a separate optional integration named `rudder-browser`. Do not
|
|
13
20
|
look for Browser tools inside `rudder-tools`, launch another browser,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "Browser"
|
|
3
3
|
short_description: "Control and test pages in Rudder Browser"
|
|
4
|
-
default_prompt: "Use $browser
|
|
4
|
+
default_prompt: "Use $browser only when the user explicitly requests Rudder's built-in Browser; then inspect this page and interact through safe high-level refs or explicit coordinate CUA."
|
|
5
5
|
|
|
6
6
|
dependencies:
|
|
7
7
|
tools:
|
|
@@ -11,4 +11,4 @@ dependencies:
|
|
|
11
11
|
transport: "stdio"
|
|
12
12
|
|
|
13
13
|
policy:
|
|
14
|
-
allow_implicit_invocation:
|
|
14
|
+
allow_implicit_invocation: false
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"query": "Use Rudder's built-in Browser to open https://example.com and report the page heading.",
|
|
4
|
+
"should_trigger": true
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"query": "Use $browser to inspect the page already open in Rudder and take a screenshot.",
|
|
8
|
+
"should_trigger": true
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"query": "Please browse https://example.com and report the page heading.",
|
|
12
|
+
"should_trigger": false
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"query": "Open the local app at http://localhost:4173 and test its login form.",
|
|
16
|
+
"should_trigger": false
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"query": "Take a screenshot of the current webpage and check whether the layout overlaps.",
|
|
20
|
+
"should_trigger": false
|
|
21
|
+
}
|
|
22
|
+
]
|
|
@@ -134,8 +134,8 @@ Read only the reference needed for the request:
|
|
|
134
134
|
installed CLI fallback catalog plus exact command semantics.
|
|
135
135
|
3. [Agent creation](references/agent-creation.md) — permission-aware Agent
|
|
136
136
|
configuration, governed hiring, approval, revision, and evidence workflow.
|
|
137
|
-
4. [Plugin authoring](references/plugin-authoring.md) —
|
|
138
|
-
|
|
137
|
+
4. [Plugin authoring](references/plugin-authoring.md) — Codex-compatible
|
|
138
|
+
package layout, manifest, Skills, MCPs, Apps, and verification workflow.
|
|
139
139
|
5. [Work practices](references/operating-practices.md) — exact
|
|
140
140
|
conditional behavior for ownership, reviews, approvals, budgets,
|
|
141
141
|
workspaces, Library handoff, authentication, and safe git use.
|
|
@@ -258,5 +258,45 @@
|
|
|
258
258
|
"expected_public_path": "https://docs.rudderhq.dev/zh/reference/permissions-and-platforms",
|
|
259
259
|
"expected_anchor": "boundaries",
|
|
260
260
|
"illustrative_case_sufficient": false
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
"query": "How does Rudder build, review, approve, and sign Windows Desktop releases?",
|
|
264
|
+
"locale": "en",
|
|
265
|
+
"query_mode": "current",
|
|
266
|
+
"expected_source_class": "official_public_docs_primary",
|
|
267
|
+
"required_contract_ids": [],
|
|
268
|
+
"expected_public_path": "https://docs.rudderhq.dev/reference/code-signing-policy",
|
|
269
|
+
"expected_anchor": null,
|
|
270
|
+
"illustrative_case_sufficient": false
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"query": "Rudder 如何构建、审查、批准并签名 Windows Desktop 发布产物?",
|
|
274
|
+
"locale": "zh",
|
|
275
|
+
"query_mode": "current",
|
|
276
|
+
"expected_source_class": "official_public_docs_primary",
|
|
277
|
+
"required_contract_ids": [],
|
|
278
|
+
"expected_public_path": "https://docs.rudderhq.dev/zh/reference/code-signing-policy",
|
|
279
|
+
"expected_anchor": null,
|
|
280
|
+
"illustrative_case_sufficient": false
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"query": "Which Rudder data stays local and which optional services process data?",
|
|
284
|
+
"locale": "en",
|
|
285
|
+
"query_mode": "current",
|
|
286
|
+
"expected_source_class": "official_public_docs_primary",
|
|
287
|
+
"required_contract_ids": ["ANALYTICS.TELEMETRY.001"],
|
|
288
|
+
"expected_public_path": "https://docs.rudderhq.dev/reference/privacy",
|
|
289
|
+
"expected_anchor": null,
|
|
290
|
+
"illustrative_case_sufficient": false
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"query": "哪些 Rudder 数据保留在本地,哪些可选服务会处理数据?",
|
|
294
|
+
"locale": "zh",
|
|
295
|
+
"query_mode": "current",
|
|
296
|
+
"expected_source_class": "official_public_docs_primary",
|
|
297
|
+
"required_contract_ids": ["ANALYTICS.TELEMETRY.001"],
|
|
298
|
+
"expected_public_path": "https://docs.rudderhq.dev/zh/reference/privacy",
|
|
299
|
+
"expected_anchor": null,
|
|
300
|
+
"illustrative_case_sufficient": false
|
|
261
301
|
}
|
|
262
302
|
]
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"should_trigger": true
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
|
-
"query": "
|
|
23
|
+
"query": "Create a Codex-compatible Rudder Plugin named quality-gate in a temporary directory with one Skill. Verify plugin.json and the current import boundary, then test the package.",
|
|
24
24
|
"should_trigger": true
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
|
-
"query": "Rudder Plugin 的
|
|
27
|
+
"query": "Rudder Plugin 的 Codex package、Skills、MCP、App、导入检查和运行权限现在有哪些边界?请查当前 authoring guide 和源码后回答。",
|
|
28
28
|
"should_trigger": true
|
|
29
29
|
},
|
|
30
30
|
{
|
|
@@ -246,8 +246,6 @@ or editing that URL by hand.
|
|
|
246
246
|
|
|
247
247
|
- `GET /api/approvals/:approvalId`
|
|
248
248
|
- `GET /api/approvals/:approvalId/issues`
|
|
249
|
-
- `GET /api/approvals/:approvalId/comments`
|
|
250
|
-
- `POST /api/approvals/:approvalId/comments`
|
|
251
249
|
- `POST /api/approvals/:approvalId/request-revision`
|
|
252
250
|
- `POST /api/approvals/:approvalId/resubmit`
|
|
253
251
|
- `POST /api/approvals/:approvalId/approve`
|