Skip to content
Closed
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
927 changes: 927 additions & 0 deletions docs/superpowers/plans/2026-03-17-v070-website-release.md

Large diffs are not rendered by default.

707 changes: 36 additions & 671 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
"dev": "concurrently \"npm run dev:vite\" \"npm run dev:electron\"",
"dev:vite": "vite",
"dev:electron": "npm run build:preload && wait-on http://localhost:5173 && electron .",
"build": "npm run build:main && npm run build:preload && npm run build:renderer",
"build:main": "esbuild src/main/index.ts --bundle --platform=node --outfile=dist/main/index.js --external:electron --external:electron-updater --external:sql.js --external:@xenova/transformers --format=cjs --target=node18 --sourcemap",
"build": "npm run build:main && npm run build:ner-worker && npm run build:preload && npm run build:renderer",
"build:main": "esbuild src/main/index.ts --bundle --platform=node --outfile=dist/main/index.js --external:electron --external:electron-updater --external:sql.js --external:@huggingface/transformers --format=cjs --target=node18 --sourcemap",
"build:ner-worker": "esbuild src/main/privacy/ner-worker.ts --bundle --platform=node --outfile=dist/main/ner-worker.js --external:@huggingface/transformers --format=cjs --target=node18 --sourcemap",
"build:preload": "esbuild src/preload/index.ts --bundle --platform=node --outfile=dist/preload/index.js --external:electron --format=iife --target=node18",
"build:renderer": "vite build",
"start": "electron .",
Expand All @@ -37,8 +38,8 @@
"dependencies": {
"@anthropic-ai/sdk": "^0.71.2",
"@google/generative-ai": "^0.24.1",
"@huggingface/transformers": "^4.2.0",
"@qdrant/js-client-rest": "^1.16.2",
"@xenova/transformers": "^2.17.2",
"electron-updater": "^6.7.3",
"lucide-react": "^0.563.0",
"nanoid": "^5.1.6",
Expand Down
8 changes: 4 additions & 4 deletions src/main/privacy/model-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class NERModelManager {

constructor(baseDir?: string) {
this.baseDir = baseDir ?? DEFAULT_BASE_DIR
// @xenova/transformers caches in {cacheDir}/{org}/{model-name}/
// @huggingface/transformers caches in {cacheDir}/{org}/{model-name}/ (same layout as @xenova v2)
this.modelDir = path.join(this.baseDir, ...MODEL_ID.split('/'))
this.status = this.checkLocalStatus()
}
Expand Down Expand Up @@ -49,14 +49,14 @@ export class NERModelManager {
try {
fs.mkdirSync(this.baseDir, { recursive: true })

const { pipeline, env } = await import('@xenova/transformers')
const { pipeline, env } = await import('@huggingface/transformers')
env.cacheDir = this.baseDir
env.allowRemoteModels = true

// Use non-quantized (fp32) model for full GIVENNAME/SURNAME detection quality.
// fp32 (non-quantized) model for full GIVENNAME/SURNAME detection quality.
// Quantized model loses name recognition. fp32 is ~1.15GB but inference is still <50ms.
const pipe = await pipeline('token-classification', MODEL_ID, {
quantized: false,
dtype: 'fp32',
progress_callback: (progress: { status: string; loaded?: number; total?: number }) => {
if (progress.status === 'progress' && progress.total) {
this.downloadProgress = Math.round(((progress.loaded ?? 0) / progress.total) * 100)
Expand Down
6 changes: 3 additions & 3 deletions src/main/privacy/ner-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ type WorkerMessage =
let pipe: any = null

async function initPipeline(modelId: string, cacheDir: string): Promise<void> {
const { pipeline, env } = await import('@xenova/transformers')
const { pipeline, env } = await import('@huggingface/transformers')
env.cacheDir = cacheDir
env.allowRemoteModels = false // model must be pre-downloaded via model-manager
// Use non-quantized (fp32) for full PII detection quality
pipe = await pipeline('token-classification', modelId, { quantized: false })
// fp32 (non-quantized) for full PII detection quality
pipe = await pipeline('token-classification', modelId, { dtype: 'fp32' })
parentPort?.postMessage({ type: 'ready' })
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/tracking/llm-cost-table.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"_version": "2026-03-10",
"_version": "2026-07-02",
"_description": "LLM provider pricing in USD per 1M tokens. Shared across Mingly and Claude Remote.",
"anthropic": {
"claude-opus-4-6": { "input": 5, "output": 25 },
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/privacy-ner-integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,15 @@ describe.skipIf(SKIP)('piiranha-v1 NER Integration', () => {
console.log('[NER Integration] Model already cached.')
}

const transformers = await import('@xenova/transformers')
const transformers = await import('@huggingface/transformers')
transformers.env.cacheDir = INTEGRATION_MODEL_DIR
transformers.env.allowRemoteModels = true // allow download of non-quantized variant

console.log('[NER Integration] Loading pipeline (fp32 for best quality)...')
pipeline = await transformers.pipeline(
'token-classification',
'onnx-community/piiranha-v1-detect-personal-information-ONNX',
{ quantized: false }
{ dtype: 'fp32' }
)
console.log('[NER Integration] Pipeline ready.')
}, 300_000)
Expand Down
4 changes: 2 additions & 2 deletions tests/red-team/helpers/direct-ner-detector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,13 @@ export async function createDirectNERDetector(): Promise<{
shutdown: () => Promise<void>
getModelManager: () => { getStatus: () => string }
}> {
const { pipeline, env } = await import('@xenova/transformers')
const { pipeline, env } = await import('@huggingface/transformers')
env.cacheDir = CACHE_DIR
env.allowRemoteModels = false

console.log('[DirectNER] Loading piiranha-v1 fp32 model...')
const startLoad = performance.now()
const pipe = await pipeline('token-classification', MODEL_ID, { quantized: false })
const pipe = await pipeline('token-classification', MODEL_ID, { dtype: 'fp32' })
console.log(`[DirectNER] Model loaded in ${Math.round(performance.now() - startLoad)}ms`)

let available = true
Expand Down
Loading