Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 32 additions & 0 deletions packages/plugins/examples/plugin-i18n-parity/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "@ocho/plugin-i18n-parity",
"version": "0.1.0",
"type": "module",
"exports": {
".": "./src/index.ts"
},
"paperclipPlugin": {
"manifest": "./dist/manifest.js",
"worker": "./dist/worker.js",
"ui": "./dist/ui"
},
"scripts": {
"prebuild": "node ../../../../scripts/ensure-plugin-build-deps.mjs",
"build": "tsc && node ./scripts/build-ui.mjs",
"clean": "rm -rf dist",
"typecheck": "pnpm --filter @paperclipai/plugin-sdk build && tsc --noEmit"
},
"dependencies": {
"@paperclipai/plugin-sdk": "workspace:*",
"cheerio": "^1.0.0"
},
"devDependencies": {
"@types/node": "^24.6.0",
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.2",
"esbuild": "^0.25.11",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"typescript": "^5.7.3"
}
}
24 changes: 24 additions & 0 deletions packages/plugins/examples/plugin-i18n-parity/scripts/build-ui.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import esbuild from "esbuild";
import path from "node:path";
import { fileURLToPath } from "node:url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const packageRoot = path.resolve(__dirname, "..");

await esbuild.build({
entryPoints: [path.join(packageRoot, "src/ui/index.tsx")],
outfile: path.join(packageRoot, "dist/ui/index.js"),
bundle: true,
format: "esm",
platform: "browser",
target: ["es2022"],
sourcemap: true,
external: [
"react",
"react-dom",
"react/jsx-runtime",
"@paperclipai/plugin-sdk/ui",
],
logLevel: "info",
});
2 changes: 2 additions & 0 deletions packages/plugins/examples/plugin-i18n-parity/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as manifest } from "./manifest.js";
export { default as worker } from "./worker.js";
163 changes: 163 additions & 0 deletions packages/plugins/examples/plugin-i18n-parity/src/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import type { PaperclipPluginManifestV1 } from "@paperclipai/plugin-sdk";

const manifest: PaperclipPluginManifestV1 = {
id: "ocho.i18n-parity",
apiVersion: 1,
version: "0.1.0",
displayName: "i18n Parity Scanner",
description:
"Scans localized HTML pages and scores translation parity per surface. Surfaces still-English content across all supported locales.",
author: "Ocho",
categories: ["automation", "connector"],
capabilities: [
"agent.tools.register",
"activity.log.write",
"ui.sidebar.register",
"ui.page.register",
"ui.dashboardWidget.register",
"companies.read",
"issues.create",
],
entrypoints: {
worker: "./dist/worker.js",
ui: "./dist/ui",
},
instanceConfigSchema: {
type: "object",
properties: {
repoPath: {
type: "string",
description:
"Absolute path to the sudokuaday.com repo root to scan.",
},
localeConfigFile: {
type: "string",
description:
"Path to the locale config JSON file, relative to repoPath. Defaults to 'config.locales.json'.",
},
minScore: {
type: "number",
description:
"Minimum weighted parity score (0–1) below which a page is flagged. Defaults to 0.7.",
},
surfaceWeights: {
type: "object",
description:
"Map of surface name to weight multiplier. Surfaces: meta, nav, hero, main, cta, footer, embeds.",
additionalProperties: { type: "number" },
},
excludePatterns: {
type: "array",
items: { type: "string" },
description:
"Glob patterns (relative to repoPath) to exclude from scanning.",
},
},
required: ["repoPath"],
},
tools: [
{
name: "run-scan",
displayName: "Run i18n Parity Scan",
description:
"Scans all localized HTML pages and returns parity scores. Accepts optional locale filter and page limit.",
parametersSchema: {
type: "object",
properties: {
locale: {
type: "string",
description:
"Locale code to scan (e.g. 'ja'). Omit to scan all non-English locales.",
},
pageLimit: {
type: "number",
description: "Maximum number of pages to scan per locale.",
},
},
},
},
{
name: "get-report",
displayName: "Get Parity Report",
description:
"Returns the full parity report (all locales, all pages) from the most recent scan.",
parametersSchema: {
type: "object",
properties: {},
},
},
{
name: "get-summary",
displayName: "Get Parity Summary",
description:
"Returns a per-locale aggregate summary from the most recent scan, sorted by score ascending.",
parametersSchema: {
type: "object",
properties: {},
},
},
{
name: "get-page-detail",
displayName: "Get Page Parity Detail",
description:
"Returns per-surface detail for a specific locale+path combination.",
parametersSchema: {
type: "object",
properties: {
locale: { type: "string", description: "Locale code, e.g. 'ja'." },
path: {
type: "string",
description: "Page path relative to locale root, e.g. 'index.html'.",
},
},
required: ["locale", "path"],
},
},
{
name: "create-tickets",
displayName: "Create Parity Tickets",
description:
"Creates Paperclip issues for pages that fall below the minScore threshold from the most recent scan.",
parametersSchema: {
type: "object",
properties: {
minScore: {
type: "number",
description:
"Override threshold (0–1). Defaults to plugin config minScore.",
},
dryRun: {
type: "boolean",
description:
"If true, returns planned ticket list without creating issues.",
},
},
},
},
Comment on lines +116 to +136
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 maxTickets parameter missing from create-tickets manifest schema

The worker's create-tickets handler reads and applies input.maxTickets (worker.ts lines 694–703), but this parameter is not declared in the manifest's parametersSchema. AI model consumers won't know it's a valid input, and Paperclip's parameter validation may reject or ignore it silently.

Suggested change
{
name: "create-tickets",
displayName: "Create Parity Tickets",
description:
"Creates Paperclip issues for pages that fall below the minScore threshold from the most recent scan.",
parametersSchema: {
type: "object",
properties: {
minScore: {
type: "number",
description:
"Override threshold (0–1). Defaults to plugin config minScore.",
},
dryRun: {
type: "boolean",
description:
"If true, returns planned ticket list without creating issues.",
},
},
},
},
{
name: "create-tickets",
displayName: "Create Parity Tickets",
description:
"Creates Paperclip issues for pages that fall below the minScore threshold from the most recent scan.",
parametersSchema: {
type: "object",
properties: {
minScore: {
type: "number",
description:
"Override threshold (0–1). Defaults to plugin config minScore.",
},
dryRun: {
type: "boolean",
description:
"If true, returns planned ticket list without creating issues.",
},
maxTickets: {
type: "number",
description:
"Cap on the number of tickets to create in a single call.",
},
},
},
},
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/plugins/examples/plugin-i18n-parity/src/manifest.ts
Line: 116-136

Comment:
**`maxTickets` parameter missing from `create-tickets` manifest schema**

The worker's `create-tickets` handler reads and applies `input.maxTickets` (worker.ts lines 694–703), but this parameter is not declared in the manifest's `parametersSchema`. AI model consumers won't know it's a valid input, and Paperclip's parameter validation may reject or ignore it silently.

```suggestion
    {
      name: "create-tickets",
      displayName: "Create Parity Tickets",
      description:
        "Creates Paperclip issues for pages that fall below the minScore threshold from the most recent scan.",
      parametersSchema: {
        type: "object",
        properties: {
          minScore: {
            type: "number",
            description:
              "Override threshold (0–1). Defaults to plugin config minScore.",
          },
          dryRun: {
            type: "boolean",
            description:
              "If true, returns planned ticket list without creating issues.",
          },
          maxTickets: {
            type: "number",
            description:
              "Cap on the number of tickets to create in a single call.",
          },
        },
      },
    },
```

How can I resolve this? If you propose a fix, please make it concise.

],
ui: {
slots: [
{
type: "sidebar",
id: "i18n-parity-sidebar",
displayName: "i18n Parity",
exportName: "I18nParitySidebar",
},
{
type: "page",
id: "i18n-parity-page",
displayName: "i18n Parity Report",
routePath: "i18n-parity",
exportName: "I18nParityPage",
},
{
type: "dashboardWidget",
id: "i18n-parity-widget",
displayName: "i18n Parity Snapshot",
exportName: "I18nParityWidget",
},
],
},
};

export default manifest;
Loading
Loading