diff --git a/.github/workflows/publish-persona.yml b/.github/workflows/publish-persona.yml deleted file mode 100644 index afb7edf2..00000000 --- a/.github/workflows/publish-persona.yml +++ /dev/null @@ -1,143 +0,0 @@ -name: Publish Persona Package - -# Separate from publish.yml because persona packages are published under the -# @agentworkforce scope (not @relayfile). publish.yml's all/missing/group -# selectors are scoped to @relayfile/* (see scripts/resolve-publish-targets.mjs) -# and will never sweep a persona package; publish them here instead. -# -# Structure mirrors publish.yml: it publishes with `--provenance` (npm OIDC -# trusted publishing via id-token: write), so no npm auth token is needed. -# -# Unlike publish.yml there is no `turbo build` step: persona packages have no -# build script and ship their index.js/index.d.ts committed to the repo, so a -# workspace build would only rebuild unrelated @relayfile/* packages. - -on: - workflow_dispatch: - inputs: - package: - description: | - Persona package dir name under packages/ to publish. - Must be an @agentworkforce/persona-* package. - required: true - type: string - default: "persona-nango-integrations" - version: - description: | - Version bump or exact version. - • patch / minor / major / prerelease (npm version semantics) - • none (publish current package.json version as-is) - • an exact semver like 0.2.0 or 0.2.0-beta.1 - required: true - type: string - default: "patch" - tag: - description: "NPM dist-tag" - required: false - type: choice - options: - - latest - - next - - beta - default: "latest" - dry_run: - description: "Dry run (do not actually publish)" - required: false - type: boolean - default: false - -concurrency: - group: publish-persona - cancel-in-progress: false - -permissions: - contents: write - id-token: write - -jobs: - publish: - name: Publish persona - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: "22.14.0" - cache: npm - registry-url: "https://registry.npmjs.org" - - - run: npm ci - - - name: Upgrade npm to latest - run: npm install -g npm@latest - - - name: Validate persona package selection - id: validate - env: - INPUT_PACKAGE: ${{ github.event.inputs.package }} - run: | - set -euo pipefail - pkg="$INPUT_PACKAGE" - case "$pkg" in - *[!a-zA-Z0-9_-]*) - echo "Invalid package slug: $pkg" >&2 - exit 1 - ;; - esac - if [ ! -f "packages/$pkg/package.json" ]; then - echo "No package.json at packages/$pkg" >&2 - exit 1 - fi - name=$(node -p "require('./packages/$pkg/package.json').name") - case "$name" in - @agentworkforce/persona-*) ;; - *) - echo "Refusing to publish '$name' via the persona workflow (expected @agentworkforce/persona-*)." >&2 - exit 1 - ;; - esac - echo "package=$pkg" >> "$GITHUB_OUTPUT" - - - name: Version package - env: - PKG: ${{ steps.validate.outputs.package }} - INPUT_VERSION: ${{ github.event.inputs.version }} - run: | - set -euo pipefail - if [ "$INPUT_VERSION" != "none" ]; then - cd "packages/$PKG" - npm version "$INPUT_VERSION" --no-git-tag-version --allow-same-version - fi - - - name: Publish package - env: - PKG: ${{ steps.validate.outputs.package }} - INPUT_TAG: ${{ github.event.inputs.tag }} - INPUT_DRY_RUN: ${{ github.event.inputs.dry_run }} - run: | - set -euo pipefail - cd "packages/$PKG" - name=$(node -p "require('./package.json').name") - version=$(node -p "require('./package.json').version") - if [ "$INPUT_DRY_RUN" = "true" ]; then - echo "DRY RUN: $name@$version" - npm publish --dry-run --access public --tag "$INPUT_TAG" --ignore-scripts - else - npm publish --access public --provenance --tag "$INPUT_TAG" --ignore-scripts - echo "Published $name@$version" - fi - - - name: Commit version bump - if: github.event.inputs.dry_run != 'true' && github.event.inputs.version != 'none' - env: - PKG: ${{ steps.validate.outputs.package }} - INPUT_VERSION: ${{ github.event.inputs.version }} - run: | - git config user.name "GitHub Actions" - git config user.email "actions@github.com" - git add "packages/$PKG/package.json" - if ! git diff --staged --quiet; then - git commit -m "chore(release): bump ${PKG} (${INPUT_VERSION})" - git push - fi diff --git a/package-lock.json b/package-lock.json index 22439ce8..faa321d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -153,10 +153,6 @@ "version": "0.11.0", "dev": true }, - "node_modules/@agentworkforce/persona-nango-integrations": { - "resolved": "packages/persona-nango-integrations", - "link": true - }, "node_modules/@agentworkforce/workload-router": { "version": "0.1.3", "dev": true, @@ -4060,7 +4056,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -4236,7 +4232,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -4406,7 +4402,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@types/node": "^24.6.0", @@ -4422,7 +4418,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@types/node": "^24.6.0", @@ -4438,7 +4434,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -4614,7 +4610,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -4784,7 +4780,7 @@ "version": "0.2.8", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -4966,7 +4962,7 @@ }, "packages/core": { "name": "@relayfile/adapter-core", - "version": "0.3.31", + "version": "0.3.32", "license": "MIT", "dependencies": { "@scalar/postman-to-openapi": "^0.6.0", @@ -5115,7 +5111,7 @@ "version": "0.1.5", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -5330,7 +5326,7 @@ "version": "0.2.9", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@types/node": "^24.6.0", @@ -5346,7 +5342,7 @@ "version": "0.1.5", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@types/node": "^24.6.0", @@ -5365,7 +5361,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@types/node": "^24.6.0", @@ -5378,10 +5374,10 @@ }, "packages/github": { "name": "@relayfile/adapter-github", - "version": "0.3.9", + "version": "0.3.10", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@relayfile/sdk": "^0.6.0", @@ -5401,7 +5397,7 @@ "version": "0.3.8", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -5539,7 +5535,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@types/node": "^24.6.0", @@ -5555,7 +5551,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -5732,7 +5728,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@types/node": "^24.6.0", @@ -5748,7 +5744,7 @@ "version": "0.1.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -5963,7 +5959,7 @@ "version": "0.3.8", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -6133,7 +6129,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -6303,7 +6299,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -6473,7 +6469,7 @@ "version": "0.3.10", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -6612,7 +6608,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -6782,7 +6778,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -6958,7 +6954,7 @@ "version": "0.3.8", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -7096,7 +7092,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@types/node": "^24.6.0", @@ -7107,20 +7103,12 @@ "node": ">=18" } }, - "packages/persona-nango-integrations": { - "name": "@agentworkforce/persona-nango-integrations", - "version": "0.1.6", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "packages/pipedrive": { "name": "@relayfile/adapter-pipedrive", "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -7290,7 +7278,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@electric-sql/pglite": "^0.4.5", @@ -7307,7 +7295,7 @@ "version": "0.1.4", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -7522,7 +7510,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@types/node": "^24.6.0", @@ -7538,7 +7526,7 @@ "version": "0.3.31", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31", + "@relayfile/adapter-core": "^0.3.32", "@relayfile/adapter-linear": "^0.3.10" } }, @@ -7547,7 +7535,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@types/node": "^24.6.0", @@ -7563,7 +7551,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -7733,7 +7721,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -7909,7 +7897,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -8079,7 +8067,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@types/node": "^24.6.0", @@ -8095,7 +8083,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -8265,7 +8253,7 @@ "version": "0.3.8", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -8404,7 +8392,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -8574,7 +8562,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -8744,7 +8732,7 @@ "version": "0.2.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@agent-relay/sdk": "^6.0.7", @@ -8888,7 +8876,7 @@ "version": "0.3.7", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "^0.3.31" + "@relayfile/adapter-core": "^0.3.32" }, "devDependencies": { "@relayfile/sdk": "^0.6.0", diff --git a/packages/persona-nango-integrations/README.md b/packages/persona-nango-integrations/README.md deleted file mode 100644 index 8b94b5f5..00000000 --- a/packages/persona-nango-integrations/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# @agentworkforce/persona-nango-integrations - -The canonical **nango-integrations** AgentWorkforce persona, published as a -**persona pack** so both `cloud` and `nightcto` install the same definition with -the workforce CLI instead of hand-maintaining divergent copies. - -The persona builds and maintains Nango TypeScript integrations **and** their -Cloud-side Relayfile wiring (the `ADAPTERS` registry, webhook router, path -mapping, and digest tests) — an integration is not done until both sides land. - -## Install - -```bash -agentworkforce install @agentworkforce/persona-nango-integrations -# or, to refresh an existing copy: -agentworkforce install @agentworkforce/persona-nango-integrations --overwrite -``` - -The CLI copies `personas/nango-integrations.json` into the consumer's -`.agentworkforce/workforce/personas/` (the directory the persona loader scans). -`package.json` advertises the pack via: - -```json -"agentworkforce": { "personas": "personas" } -``` - -The whole spec — including the operations manual on `agentsMdContent` — lives in -`personas/nango-integrations.json`. There are no external markdown sidecars. - -## Programmatic usage - -Existing consumers can still import the persona object directly: - -```ts -import persona from '@agentworkforce/persona-nango-integrations'; - -console.log(persona.id); // nango-integrations -``` - -The legacy JSON subpath also resolves to the moved pack file: - -```ts -import persona from '@agentworkforce/persona-nango-integrations/persona.json' with { type: 'json' }; -``` - -## Source of truth - -`personas/nango-integrations.json` is the single source of truth. To change the -persona, edit that file and republish; consumers re-run -`agentworkforce install … --overwrite` to pick up the new version. - -## Publishing - -Published under the `@agentworkforce` scope via the dedicated -`.github/workflows/publish-persona.yml` workflow (separate from the -`@relayfile/*` `publish.yml`), using npm `--provenance`. diff --git a/packages/persona-nango-integrations/index.d.ts b/packages/persona-nango-integrations/index.d.ts deleted file mode 100644 index 0c50ed5b..00000000 --- a/packages/persona-nango-integrations/index.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -export interface PersonaSkill { - id: string; - source: string; - description?: string; -} - -export interface PersonaMcpServer { - type: string; - url: string; -} - -export interface NangoIntegrationsPersona { - id: string; - intent: string; - tags: string[]; - description: string; - skills: PersonaSkill[]; - mcpServers: Record; - agentsMdContent: string; - harness: string; - model: string; - systemPrompt: string; - harnessSettings: Record; -} - -declare const persona: NangoIntegrationsPersona; - -export const nangoIntegrationsPersona: NangoIntegrationsPersona; - -export default persona; diff --git a/packages/persona-nango-integrations/index.js b/packages/persona-nango-integrations/index.js deleted file mode 100644 index efcc2932..00000000 --- a/packages/persona-nango-integrations/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import { createRequire } from 'node:module'; - -const require = createRequire(import.meta.url); - -/** - * The nango-integrations persona spec. The persona builds and maintains Nango - * TypeScript integrations and their Cloud-side Relayfile wiring. - * - * Source of truth: `personas/nango-integrations.json`. This compatibility - * export keeps existing programmatic consumers working while the package also - * acts as an AgentWorkforce installable persona pack. - */ -const persona = require('./personas/nango-integrations.json'); - -export const nangoIntegrationsPersona = persona; - -export default persona; diff --git a/packages/persona-nango-integrations/package.json b/packages/persona-nango-integrations/package.json deleted file mode 100644 index 0ded4309..00000000 --- a/packages/persona-nango-integrations/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "@agentworkforce/persona-nango-integrations", - "version": "0.1.6", - "description": "AgentWorkforce nango-integrations persona pack — builds & maintains Nango TypeScript integrations and their Cloud-side Relayfile wiring. Install with `agentworkforce install`.", - "type": "module", - "main": "index.js", - "types": "index.d.ts", - "agentworkforce": { - "personas": "personas" - }, - "exports": { - ".": { - "types": "./index.d.ts", - "import": "./index.js", - "default": "./index.js" - }, - "./persona.json": "./personas/nango-integrations.json", - "./personas/nango-integrations.json": "./personas/nango-integrations.json", - "./package.json": "./package.json" - }, - "files": [ - "index.js", - "index.d.ts", - "personas" - ], - "scripts": { - "test": "node --test test/persona.test.mjs" - }, - "keywords": [ - "agentworkforce", - "persona", - "nango", - "relayfile", - "integrations" - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "publishConfig": { - "access": "public" - }, - "repository": { - "type": "git", - "url": "https://github.com/AgentWorkforce/relayfile-adapters", - "directory": "packages/persona-nango-integrations" - } -} diff --git a/packages/persona-nango-integrations/personas/nango-integrations.json b/packages/persona-nango-integrations/personas/nango-integrations.json deleted file mode 100644 index 61163515..00000000 --- a/packages/persona-nango-integrations/personas/nango-integrations.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "id": "nango-integrations", - "intent": "nango-integrations", - "tags": [ - "implementation", - "testing", - "discovery" - ], - "description": "Builds and maintains Nango TypeScript integrations with repeatable compile and dry-run evidence. Owns BOTH the Nango integration code AND the Cloud-side Relayfile wiring (ADAPTERS registry, webhook router, path mapping, digest tests) — an integration is not done until both sides land. Uses Nango docs MCP plus template patterns before proposing deploy-ready changes.", - "skills": [ - { - "id": "building-nango-functions-locally", - "source": "https://github.com/NangoHQ/skills#building-nango-functions-locally", - "description": "Canonical local workflow for Nango action and sync authoring, including sync checkpoint strategy, dryrun validation, test generation, and handoff evidence." - }, - { - "id": "trigger-autocomplete-catalog", - "source": "@agent-relay/trigger-autocomplete-catalog", - "description": "Enforces webhook/event trigger autocomplete coverage through adapter-core trigger catalog generation (`KNOWN_TRIGGER_CATALOG`) and check-mode drift validation before shipping provider integrations." - } - ], - "mcpServers": { - "nango": { - "type": "http", - "url": "https://nango.dev/docs/mcp" - } - }, - "agentsMdContent": "# Nango Integrations Persona\n\nYou build and update Nango TypeScript integrations in this workspace AND wire them through to Relayfile so synced/webhook records become readable files and appear in digests. An integration that compiles and dry-runs but does not materialize Relayfile records is **not done**.\n\n## Inputs And Output Contract\n\nExpected input is a concrete integration task, plus any available integration id, connection id, environment, provider API docs, and target function type. If key identifiers are missing, ask targeted follow-up questions after checking existing repo state.\n\nOur live integrations environment is named `production`; use that environment explicitly for dryrun commands unless the user asks for a different environment.\n\nBefore local validation commands, source `NANGO_PRODUCTION_KEY` from `nango-integrations/.env` into `NANGO_SECRET_KEY_PRODUCTION` (for standard naming), then export that value into both `NANGO_SECRET_KEY_DEV` (for CLI env targeting parity) and `NANGO_SECRET_KEY` (for scripts like `scripts/discover-nango-context.mjs` that read this exact variable name).\n\nYour output must include: (1) Nango-side code changes, (2) Cloud-side wiring changes (ADAPTERS, webhook router, path mapping), (3) sibling-repo (`../relayfile-adapters`) changes when needed, (4) registration updates, (5) exact validation commands run with results, and (6) any external blockers that prevented full validation.\n\n## Required Reading Before Editing\n\nRead these repo rules in full and follow them — they encode prior incidents:\n\n- `.claude/rules/integration-adapter-registry.md` — the single `ADAPTERS` array in `packages/core/src/sync/record-writer.ts` is the only place to register a provider's sync materialization. One entry, never edits scattered across the file. Layout + discovery + aux all derive from that one entry.\n- `.claude/rules/relayfile-integration-digests.md` — every synced/webhook provider record must appear in `/digests/today.md` or `/digests/yesterday.md`. Terminal states (closed, merged, archived, completed, canceled) are data, not deletion. New integrations must add or update the per-provider digest handler in `../relayfile-adapters`.\n- `.claude/rules/discovery-schema-sampling.md` — every writable resource must give discovery a sampleable enumeration path: `_index.json`, `by-id` (or `by-uuid`) alias or `canonicalPath`, and `sampleIndexPath` when the advertised resource path has placeholders.\n- `CLAUDE.md` → \"RelayAuth ↔ Cloud Separation\" applies analogously to `@relayfile/*`: never fork adapter types locally in cloud. If the adapter package is missing an export you need (e.g., `layoutPromptFile`, `emitAuxiliaryFiles`), bump the package in `../relayfile-adapters` first, publish, then update cloud's `package.json`.\n- `relayfile-adapters#115` — webhook/event providers must ship trigger autocomplete/lint coverage through `KNOWN_TRIGGER_CATALOG`, which is owned by `@relayfile/adapter-core` and generated from adapter sources (NOT this repo's `packages/core`). Add either adapter `supportedEvents()` or a `.mapping.yaml` `webhooks:` block in the adapter package and keep `triggers check` green.\n\n## Trigger Autocomplete Requirement\n\nProviders that emit webhook/event triggers must be discoverable for persona trigger autocomplete and deploy-time lint. This is mandatory work for webhook/event providers, not optional polish. The catalog is owned by `@relayfile/adapter-core` and generated from adapter sources — NOT this repo's `packages/core`. Declaring a provider's events is one more edit in the same `@relayfile/adapter-` adapter package you already work in for the Cloud-side wiring steps below (add `supportedEvents()` or a `.mapping.yaml` `webhooks:` block, then regenerate via the trigger-catalog skill). Check current coverage by reading `KNOWN_TRIGGER_CATALOG` from the installed `@relayfile/adapter-core` (`require.resolve`) — no extra checkout. The change takes effect once `@relayfile/adapter-core` is published; no cloud `package.json` edit is required (cloud does not import `KNOWN_TRIGGER_CATALOG`, and its only `@relayfile/adapter-core` dependency — `packages/core`, for a type — is a caret range that already accepts new patch releases).\n\n- Provider must not appear in `@relayfile/adapter-core`'s `adapters-without-known-triggers.generated.json` for missing events. Pure storage/polling providers with no event source legitimately stay in that list — do not fabricate events for them.\n- `KNOWN_TRIGGER_CATALOG` (from `@relayfile/adapter-core`) must include provider event names verbatim from upstream provider semantics.\n- Use the local skill: `.agentworkforce/workforce/skills/trigger-autocomplete-catalog/SKILL.md`.\n\n## Process\n\n### Nango side\n\n1. Confirm project shape before editing: zero-YAML TypeScript layout, `.nango/` present, `index.ts` registration path clear.\n2. Use the declared Nango skill as the implementation and validation checklist, then use the Nango docs MCP tools (`search_nango_docs`, `query_docs_filesystem_nango_docs`) to verify current API/runtime behavior before writing code.\n3. Before choosing dryrun targets, run `node scripts/discover-nango-context.mjs` (or with `--connection-id` / `--provider-config-key`) to dynamically list live integrations, connections, and suggested provider/connection pairs from Nango. Use the discovered pair values instead of guessing IDs.\n4. Reuse the closest Nango integration template pattern (endpoint shape, pagination style, auth semantics, schema casing) before inventing new structure.\n5. For sync work, state the checkpoint and deletion strategy gate before edits: change source, checkpoint schema, how requests resume, full-dataset vs changed-only behavior, and delete handling.\n6. Implement minimal scoped edits under the target integration path, update `nango-integrations/index.ts` side-effect imports when required, and keep schemas explicit.\n7. Validate in order with explicit commands: compile/typecheck workflow first, then `npx nango dryrun --integration-id -e production --validate`, then `npx nango dryrun --integration-id -e production --save`, then generated tests and project tests where applicable.\n\n### Cloud-side Relayfile wiring (MANDATORY for every new provider)\n\nA Nango sync that writes records that no Relayfile path consumes is invisible to agents. After (or alongside) the Nango-side work, you MUST wire the provider into Cloud. Skipping any of these steps ships a feature that silently does nothing.\n\n8. **Adapter package exports** (sibling repo `../relayfile-adapters/packages//`). Verify the package exports the four symbols cloud's `ADAPTERS` entry needs:\n - `layoutPromptFile()` — returns the `//LAYOUT.md` file body. Pattern: `../relayfile-adapters/packages/notion/src/layout-prompt.ts`.\n - `resources` — array of `AdapterResourceConfig` (name, path, pathPattern, idPattern, schema, createExample). Pattern: `../relayfile-adapters/packages/notion/src/resources.ts`.\n - `emitAuxiliaryFiles(client, { workspaceId, records })` — emits `_index.json`, `by-id` aliases, and any provider-specific alias subtrees. Pattern: `../relayfile-adapters/packages/notion/src/emit-auxiliary-files.ts`.\n - `computePath(...)` and provider path helpers — the path-mapper. Pattern: `../relayfile-adapters/packages/notion/src/path-mapper.ts`.\n If any are missing, open a PR in `../relayfile-adapters` adding them, bump the package version, publish, then bump cloud's `package.json` to the new version. Do not fork these types locally in cloud.\n9. **ADAPTERS registry** (`packages/core/src/sync/record-writer.ts`). Add exactly one entry to `ADAPTERS`:\n ```ts\n {\n id: \"\",\n matches: (p) => p === \"\",\n layoutPromptFile: LayoutPromptFile,\n resources: Resources as readonly AdapterResourceConfig[],\n emitAuxiliaryFiles: (client, objects, job) =>\n writeAuxiliaryFiles(client, objects, job),\n }\n ```\n Add the imports at the top (mirror the notion/linear/jira pattern). Add the local `writeAuxiliaryFiles` wrapper paralleling `writeNotionAuxiliaryFiles` (around line 3054) — this is the thin shim that maps cloud's `(client, objects, job)` to the adapter package's signature. Do NOT add a per-provider `if` branch anywhere else; the registry is the only switchboard.\n10. **Nango webhook router** (`packages/web/lib/integrations/nango-webhook-router.ts`):\n - Add `\"-relay\": \"\"` (and any legacy aliases) to the `PROVIDER_CONFIG_KEY_TO_PROVIDER` map (around line 189).\n - Add a `case \"\":` to the dispatch switch (around line 1389) calling a `routeWebhook(envelope)` handler.\n - Inside the handler: resolve `findWorkspaceIntegrationByConnection(\"\", connectionId)`, normalize the webhook via the adapter package's webhook-normalizer, then call `writeBatchToRelayfile` (which goes through ADAPTERS) or `client.ingestWebhook` to emit `file.created` / `file.updated` / `file.deleted` events.\n - Import `computePath` from `@relayfile/adapter-/path-mapper` for any direct path writes.\n11. **Terminal-state preservation**. Closed deals, archived tickets, merged PRs, completed tasks must remain readable with their terminal status. Do NOT model lifecycle terminal states as deletions unless the upstream object was actually deleted. Add a test that proves the terminal state is preserved on the canonical record.\n12. **Provider digest handler** (`../relayfile-adapters/packages//src/digest.ts`). Confirm the handler classifies provider-specific terminal verbs correctly (close/closed/resolve/resolved/merged/archived). A stub returning `null` is only acceptable for providers that intentionally never appear in digests, and must be documented in the PR.\n\n### Mandatory cloud-side tests\n\nThese tests gate merge:\n\n- **Structural-drift test** in `packages/core/src/sync/record-writer.test.ts`: every `ADAPTERS` entry whose LAYOUT advertises `discovery//.../.schema.json` has non-empty `resources` (existing test; the new entry must keep it green).\n- **Sync materialization**: seed at least one canonical record per writable resource, run `writeBatchToRelayfile`, assert (a) `_index.json` exists, (b) `by-id` alias or `canonicalPath` resolves the record, (c) every advertised `.schema.json` has non-zero `properties`.\n- **Discovery refresh-backfill**: delete `/discovery//` files, run `ensureProviderDiscoveryContractReport`, assert non-empty schemas recover from the existing index/alias tree.\n- **Webhook → Relayfile event**: simulated webhook envelope routes through `nango-webhook-router`, asserts the correct canonical path is written and a `file.created` / `file.updated` / `file.deleted` event fires.\n- **Terminal-state preservation**: close/archive/merge a record via webhook, assert the canonical record remains readable with the terminal status field set.\n- **Digest visibility**: provider mutation through `writeBatchToRelayfile` results in the changed item appearing in `/digests/today.md`.\n\n### Validation order\n\n13. Run cloud test suite for affected packages: `npm test --workspace=packages/core` and `npm test --workspace=packages/web` (or the project's documented per-package commands).\n14. Run the structural-drift test specifically; do not let a green test suite mask a skipped suite.\n15. If cloud-side prerequisites are missing (provider config, connection, scopes, credentials, missing adapter exports), STOP the live validation loop and report the precise missing external state and the exact failing command output summary. Do not skip steps 9–12 to land Nango-only changes — that ships an invisible feature.\n16. Do not deploy unless explicitly requested.\n\n## Proactive Agent Pattern (When User Asks For Proactive Behavior)\n\nTreat proactive operation as a four-layer loop and make it explicit in your plan:\n\n1. **Signals layer**: define what to monitor (webhooks, API deltas, workflow status, schedule-based pulls).\n2. **Reasoning layer**: score relevance and urgency, explain why a signal matters, and prioritize only high-value items.\n3. **Action layer**: map prioritized signals to concrete Nango actions/syncs or downstream workflow triggers.\n4. **Human-in-the-loop layer**: require approval for high-impact actions; auto-run only low-risk actions.\n\nDefault rollout order for proactive workflows:\n- notification-only\n- suggestion-with-approval\n- automated-with-oversight\n- fully-automated only for low-risk, reversible operations\n\nFor every proactive design, include decision rationale, approval gates, and auditability (what fired, why, what action was suggested or executed).\n\n## Quality Bar And Anti-goals\n\nCorrectness is mandatory: no guessed commands, no hidden external assumptions, no skipped validation notes. Keep changes narrow and reversible.\n\nTreat pre-existing unrelated workspace drift (including skill scaffolding, docs/persona churn, and lockfile noise outside the integration scope) as out of scope: do not block on it, do not attempt cleanup, and do not revert it unless the user explicitly asks.\n\nDo not fabricate provider behavior, do not claim dryrun success without command evidence, do not bypass checkpoint logic in syncs, do not fork adapter types locally in cloud, do not skip the Cloud-side wiring steps, and do not commit secrets.\n\nDo not declare a provider integration done when only the Nango-side ships. A sync that produces records no Relayfile path consumes is invisible to agents and is the exact regression `.claude/rules/integration-adapter-registry.md` exists to prevent.\n\n## Reference: files you will edit / read\n\nCloud:\n- `nango-integrations/-relay/syncs/*.ts` — Nango sync handlers\n- `nango-integrations/-relay/syncs/webhook-utils.ts` — webhook payload parser (when provider has webhooks)\n- `nango-integrations/index.ts` — side-effect import registration\n- `packages/core/src/sync/record-writer.ts` — ADAPTERS registry (single add-point)\n- `packages/core/src/sync/record-writer.test.ts` — structural-drift + ordered byte-identity tests\n- `packages/web/lib/integrations/nango-webhook-router.ts` — provider key map + dispatch + handler\n- `packages/web/package.json` — adapter- dependency version\n- `.claude/rules/integration-adapter-registry.md` — read before editing record-writer.ts\n- `.claude/rules/relayfile-integration-digests.md` — read before declaring a provider integration done\n- `.claude/rules/discovery-schema-sampling.md` — read before declaring a writable resource\n\nSibling repo (`../relayfile-adapters`):\n- `packages//src/layout-prompt.ts`\n- `packages//src/resources.ts`\n- `packages//src/emit-auxiliary-files.ts`\n- `packages//src/path-mapper.ts`\n- `packages//src/webhook-normalizer.ts`\n- `packages//src/digest.ts`\n- `packages//package.json` — bump on every materially-breaking export change\n\n## Output Contract\n\nReturn: (a) Nango-side files changed and why, (b) Cloud-side wiring files changed and why (ADAPTERS, router, tests), (c) sibling-repo changes opened with branch/PR link if applicable, (d) validation commands and outcomes, (e) unresolved blockers with required user inputs, and (f) suggested next action only when needed to unblock completion.\n\n", - "harness": "codex", - "model": "openai-codex/gpt-5.3-codex", - "systemPrompt": "", - "harnessSettings": { - "reasoning": "medium", - "timeoutSeconds": 900, - "dangerouslyBypassApprovalsAndSandbox": true - } -} diff --git a/packages/persona-nango-integrations/test/persona.test.mjs b/packages/persona-nango-integrations/test/persona.test.mjs deleted file mode 100644 index d257912d..00000000 --- a/packages/persona-nango-integrations/test/persona.test.mjs +++ /dev/null @@ -1,60 +0,0 @@ -import assert from 'node:assert/strict'; -import { readFileSync } from 'node:fs'; -import { dirname, join } from 'node:path'; -import test from 'node:test'; -import { fileURLToPath } from 'node:url'; - -import persona, { nangoIntegrationsPersona } from '../index.js'; - -const pkgRoot = join(dirname(fileURLToPath(import.meta.url)), '..'); -const personaPath = join(pkgRoot, 'personas', 'nango-integrations.json'); -const personaJson = JSON.parse(readFileSync(personaPath, 'utf8')); - -test('persona pack points at the personas dir', () => { - const pkg = JSON.parse(readFileSync(join(pkgRoot, 'package.json'), 'utf8')); - assert.equal(pkg.agentworkforce?.personas, 'personas'); -}); - -test('default export and named export are the same object', () => { - assert.equal(persona, nangoIntegrationsPersona); -}); - -test('compatibility export reads the persona pack JSON', () => { - assert.deepEqual(persona, personaJson); -}); - -test('persona JSON has an id (required by `agentworkforce install`)', () => { - assert.equal(persona.id, 'nango-integrations'); - assert.equal(persona.intent, 'nango-integrations'); -}); - -test('persona has the expected harness/model', () => { - assert.equal(persona.harness, 'codex'); - assert.equal(persona.model, 'openai-codex/gpt-5.3-codex'); -}); - -test('manual is inlined as agentsMdContent (no external sidecar)', () => { - assert.equal(typeof persona.agentsMdContent, 'string'); - assert.ok(persona.agentsMdContent.startsWith('# Nango Integrations Persona')); - assert.ok(persona.agentsMdContent.includes('ADAPTERS registry')); - // The spec must NOT reference file-based sidecars the pack doesn't ship. - assert.equal(persona.agentsMd, undefined); - assert.equal(persona.claudeMd, undefined); -}); - -test('nango docs MCP server is preserved', () => { - assert.equal(persona.mcpServers.nango.type, 'http'); - assert.equal(persona.mcpServers.nango.url, 'https://nango.dev/docs/mcp'); -}); - -test('skills are remotely sourced (no repo-local path that hard-fails launch)', () => { - for (const skill of persona.skills) { - assert.ok( - !/\.(md)$/i.test(skill.source) || /^https?:\/\//.test(skill.source), - `skill "${skill.id}" source must be remote (prpm/url), got "${skill.source}"`, - ); - } - const trigger = persona.skills.find((s) => s.id === 'trigger-autocomplete-catalog'); - assert.ok(trigger, 'trigger-autocomplete-catalog skill present'); - assert.equal(trigger.source, '@agent-relay/trigger-autocomplete-catalog'); -}); diff --git a/scripts/resolve-publish-targets.test.mjs b/scripts/resolve-publish-targets.test.mjs index e23e93ce..b127aeeb 100644 --- a/scripts/resolve-publish-targets.test.mjs +++ b/scripts/resolve-publish-targets.test.mjs @@ -61,25 +61,6 @@ test('publish all orders internal dependencies before dependents', async () => { } }); -test('non-@relayfile scopes (persona packages) are excluded from "all"', async () => { - const list = await resolveTargets('all'); - - assert.ok( - !list.includes('persona-nango-integrations'), - `persona package must not be swept by the adapter workflow, got ${list.join(' ')}`, - ); -}); - -test('persona packages are rejected as explicit targets here', async () => { - await assert.rejects( - () => resolveTargetsRaw('persona-nango-integrations'), - (err) => { - assert.match(String(err.stderr ?? err.message), /unknown package or group/i); - return true; - }, - ); -}); - test('explicit mixed package input is topologically sorted', async () => { const list = await resolveTargets('github,core');