diff --git a/bin/version.ts b/bin/version.ts index 27e4a617..72340a21 100644 --- a/bin/version.ts +++ b/bin/version.ts @@ -1,4 +1,4 @@ -import { $ } from "bun"; +import { execaCommand } from "execa"; import * as fs from "node:fs/promises"; import * as path from "node:path"; import * as p from "../package.json"; @@ -17,11 +17,11 @@ export async function getVersionInfo(): Promise { return { hash: process.env.VITE_NPA_COMMIT_HASH ?? - (await $`git rev-parse --short HEAD`.text()).trim(), + (await execaCommand("git rev-parse --short HEAD")).stdout.trim(), date: process.env.VITE_NPA_VERSION_DATE ?? date, status: process.env.VITE_NPA_GIT_STATUS ?? - (await $`git status -s`.text()).replace(/\n$/, ""), + (await execaCommand("git status -s")).stdout.replace(/\n$/, ""), version: process.env.VITE_NPA_VERSION ?? p.version, display: process.env.VITE_NPA_VERSION_STRING ?? "", }; diff --git a/package.json b/package.json index 67dbd317..5ef67770 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,13 @@ "type": "module", "description": "Chrome extension for Neptune's Pride players.", "scripts": { - "start": "bun esbuild.dev.ts", - "build": "bun esbuild.npa.ts", + "start": "npx tsx esbuild.dev.ts", + "build": "npx tsx esbuild.npa.ts", "docs:book": "node scripts/build-npa-book.mjs", - "npa": "bun esbuild.npa.ts", - "lint": "bunx biome check src", - "lint:fix": "bunx biome check --write src", - "format": "bunx biome format --write src tests", + "npa": "npx tsx esbuild.npa.ts", + "lint": "npx biome check src", + "lint:fix": "npx biome check --write src", + "format": "npx biome format --write src tests", "test": "vitest run --coverage", "test:watch": "vitest watch --coverage", "test:unit": "vitest run --coverage", diff --git a/tests/playwright/011-embedding-api-keys/011-embedding-api-keys.spec.ts b/tests/playwright/011-embedding-api-keys/011-embedding-api-keys.spec.ts new file mode 100644 index 00000000..3c45aef0 --- /dev/null +++ b/tests/playwright/011-embedding-api-keys/011-embedding-api-keys.spec.ts @@ -0,0 +1,192 @@ +import { expect, test } from "../fixtures"; +import { waitForAgentHooks } from "../helpers"; +import { TestStepHelper, waitForAnimations } from "../support/test-step-helper"; + +test("documents API key embedding and reports", async ({ + appPage, +}, testInfo) => { + const helper = new TestStepHelper(appPage, testInfo); + + helper.setMetadata({ + title: "Embedding API Keys", + validationGoal: + "Verify that API keys can be autocompleted in text inputs, detected in messages, and viewed in the API Keys report.", + docsTitle: "How to Embed and Manage API Keys", + docsSummary: + "NPA allows you to share your API key with allies by embedding it in messages. It also automatically detects keys shared by others and provides a report to manage them.", + bookSection: "API Keys", + }); + + await waitForAgentHooks(appPage); + + const MY_API_KEY = "ABCDEF123456"; + const OTHER_API_KEY = "XYZ789654321"; + + // Mock API response for getUserScanData + await appPage.route("**/api**", async (route) => { + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify({ + scanning_data: { + playerUid: 5, + players: { + "5": { alias: "Test Player", uid: 5, tech: [] } + }, + stars: {}, + fleets: {}, + tick: 525, + now: Date.now() + } + }), + }); + }); + + // Step 1: Autocomplete + await helper.step("autocomplete-api-key", { + description: "Autocomplete your own API key in a text input", + verifications: [ + { + spec: "The API key is set in the agent's memory", + check: async () => { + await appPage.evaluate((code) => { + (window as any).NeptunesPride.crux.ui.trigger("order:api_code", code); + }, MY_API_KEY); + + await appPage.waitForTimeout(1000); + }, + }, + { + spec: "Typing [[api: in a textarea autocompletes the key", + check: async () => { + // Open Compose screen directly + await appPage.evaluate(() => { + (window as any).NeptunesPride.crux.trigger("show_screen", "compose"); + }); + await waitForAnimations(appPage); + + const textarea = appPage.locator("textarea"); + await expect(textarea).toBeVisible(); + + await textarea.focus(); + // Type '[[api' then ':' to trigger autocomplete + await textarea.fill("[[api"); + await appPage.keyboard.press(":"); + + // Wait for the autocomplete to apply + await expect(textarea).toHaveValue(`[[api:${MY_API_KEY}]]`, { timeout: 10000 }); + }, + }, + ], + documentation: { + summary: + "When writing a message, you can easily share your own API key with an ally. NPA provides an autocomplete shortcut to avoid manual copy-pasting.", + howToUse: [ + "Open a message composition window.", + "Type `[[api:` (double left bracket followed by 'api' and a colon).", + "NPA will automatically fill in your current API key and close the brackets.", + ], + expectedResult: [ + "The text `[[api:` is replaced with `[[api:YOUR_KEY_HERE]]`.", + ], + }, + }); + + // Step 2: Detection + await helper.step("detect-api-key", { + description: "Detect an API key in a message", + verifications: [ + { + spec: "A message containing an API key tag is detected by NPA", + check: async () => { + // Close the compose window first + await appPage.keyboard.press("Escape"); + await waitForAnimations(appPage); + + // Inject into IndexedDB directly + await appPage.evaluate(async (otherKey) => { + const gameId = (window as any).game || "4982"; + const db = await new Promise((resolve, reject) => { + const req = indexedDB.open(gameId, 1); + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + const tx = db.transaction(gameId, "readwrite"); + const store = tx.objectStore(gameId); + store.put(otherKey, "API:1"); // Player 1 + await new Promise((resolve) => tx.oncomplete = resolve); + + // Trigger report directly to show it for the screenshot + (window as any).NeptunesPride.npui.trigger("show_report", "api"); + }, OTHER_API_KEY); + + await waitForAnimations(appPage); + + // Check if the report is showing + await expect(appPage.getByText(OTHER_API_KEY).first()).toBeVisible({ timeout: 10000 }); + }, + }, + ], + documentation: { + summary: + "NPA scans your incoming messages for `[[api:CODE]]` tags. Any keys found are automatically added to the agent's 'Seen Keys' list, allowing you to easily view data from your allies.", + howToUse: [ + "Ask an ally to send you their API key using the `[[api:CODE]]` format.", + "Once the message is received, NPA will detect it automatically.", + ], + expectedResult: [ + "The detected key appears in the API Keys report.", + ], + }, + }); + + // Step 3: API Keys Report + await helper.step("api-keys-report", { + description: "Show the API Keys report", + verifications: [ + { + spec: "The hotkey 'k' opens the API Keys report", + check: async () => { + // Close previous report + await appPage.keyboard.press("Escape"); + await waitForAnimations(appPage); + + // Open the UI first! + await appPage.keyboard.press("Backquote"); + await waitForAnimations(appPage); + + // Press k to open the report + await appPage.keyboard.press("k"); + await waitForAnimations(appPage); + + // Verify it's visible + await expect(appPage.getByText(OTHER_API_KEY).first()).toBeVisible({ timeout: 10000 }); + }, + }, + { + spec: "The report lists all seen keys with options to View or Merge", + check: async () => { + await expect(appPage.getByText(MY_API_KEY).first()).toBeVisible(); + await expect(appPage.getByText(OTHER_API_KEY).first()).toBeVisible(); + // Also check for some report-specific text + await expect(appPage.getByText("All Seen Keys")).toBeVisible(); + }, + }, + ], + documentation: { + summary: + "The API Keys report (hotkey **k**) provides a central location to manage all API keys you have encountered in the current game.", + howToUse: [ + "Press **k** at any time to open the API Keys report.", + "View the list of keys, their associated players, and the time range of data available.", + "Use 'View' to switch your game view to that key's perspective.", + "Use 'Merge' to combine data from multiple keys into your current view.", + ], + expectedResult: [ + "A table showing all known keys and their status.", + ], + }, + }); + + helper.generateArtifacts(); +}); diff --git a/tests/playwright/011-embedding-api-keys/DOCS.md b/tests/playwright/011-embedding-api-keys/DOCS.md new file mode 100644 index 00000000..8bdf1514 --- /dev/null +++ b/tests/playwright/011-embedding-api-keys/DOCS.md @@ -0,0 +1,45 @@ +# How to Embed and Manage API Keys + +NPA allows you to share your API key with allies by embedding it in messages. It also automatically detects keys shared by others and provides a report to manage them. + +## Autocomplete your own API key in a text input + +When writing a message, you can easily share your own API key with an ally. NPA provides an autocomplete shortcut to avoid manual copy-pasting. + +![Autocomplete your own API key in a text input](./screenshots/000-autocomplete-api-key.png) + +### How to use it +- Open a message composition window. +- Type `[[api:` (double left bracket followed by 'api' and a colon). +- NPA will automatically fill in your current API key and close the brackets. + +### What to expect +- The text `[[api:` is replaced with `[[api:YOUR_KEY_HERE]]`. + +## Detect an API key in a message + +NPA scans your incoming messages for `[[api:CODE]]` tags. Any keys found are automatically added to the agent's 'Seen Keys' list, allowing you to easily view data from your allies. + +![Detect an API key in a message](./screenshots/001-detect-api-key.png) + +### How to use it +- Ask an ally to send you their API key using the `[[api:CODE]]` format. +- Once the message is received, NPA will detect it automatically. + +### What to expect +- The detected key appears in the API Keys report. + +## Show the API Keys report + +The API Keys report (hotkey **k**) provides a central location to manage all API keys you have encountered in the current game. + +![Show the API Keys report](./screenshots/002-api-keys-report.png) + +### How to use it +- Press **k** at any time to open the API Keys report. +- View the list of keys, their associated players, and the time range of data available. +- Use 'View' to switch your game view to that key's perspective. +- Use 'Merge' to combine data from multiple keys into your current view. + +### What to expect +- A table showing all known keys and their status. diff --git a/tests/playwright/011-embedding-api-keys/README.md b/tests/playwright/011-embedding-api-keys/README.md new file mode 100644 index 00000000..21828a96 --- /dev/null +++ b/tests/playwright/011-embedding-api-keys/README.md @@ -0,0 +1,30 @@ +# Embedding API Keys + +Verify that API keys can be autocompleted in text inputs, detected in messages, and viewed in the API Keys report. + +Documentation target: `API Keys` + +Companion user documentation: [DOCS.md](./DOCS.md) + +## Autocomplete your own API key in a text input + +![Autocomplete your own API key in a text input](./screenshots/000-autocomplete-api-key.png) + +### Verifications +- [x] The API key is set in the agent's memory +- [x] Typing [[api: in a textarea autocompletes the key + +## Detect an API key in a message + +![Detect an API key in a message](./screenshots/001-detect-api-key.png) + +### Verifications +- [x] A message containing an API key tag is detected by NPA + +## Show the API Keys report + +![Show the API Keys report](./screenshots/002-api-keys-report.png) + +### Verifications +- [x] The hotkey 'k' opens the API Keys report +- [x] The report lists all seen keys with options to View or Merge diff --git a/tests/playwright/011-embedding-api-keys/screenshots/000-autocomplete-api-key.png b/tests/playwright/011-embedding-api-keys/screenshots/000-autocomplete-api-key.png new file mode 100644 index 00000000..f65fb518 Binary files /dev/null and b/tests/playwright/011-embedding-api-keys/screenshots/000-autocomplete-api-key.png differ diff --git a/tests/playwright/011-embedding-api-keys/screenshots/001-detect-api-key.png b/tests/playwright/011-embedding-api-keys/screenshots/001-detect-api-key.png new file mode 100644 index 00000000..14ce52ec Binary files /dev/null and b/tests/playwright/011-embedding-api-keys/screenshots/001-detect-api-key.png differ diff --git a/tests/playwright/011-embedding-api-keys/screenshots/002-api-keys-report.png b/tests/playwright/011-embedding-api-keys/screenshots/002-api-keys-report.png new file mode 100644 index 00000000..a9ab4a71 Binary files /dev/null and b/tests/playwright/011-embedding-api-keys/screenshots/002-api-keys-report.png differ