test(connector-id): migrate fixtures and assertions to pi-mono ids

Replaces legacy adapter ids (codex_local / claude_local / gemini_local /
claude_compatible) across ~42 test files with pi-mono equivalents:
- codex_local → openai-codex
- claude_local → claude-pro
- gemini_local → gemini-cli
- claude_compatible → anthropic

Hand-rewrites where fixture semantics changed:
- connector-matching: TASK_TYPE_PREFERENCE ordering rebased (claude-pro
  first for code/content/management; google first for research)
- connector-model-policy: getModels(provider) from pi-ai instead of the
  deleted adapter.module.models array
- session-management + edge-case-session: adapter exemption removed;
  rotation now uniform under pi-mono
- ipc-core-admin-handlers: CSV compat model replaced with pi-ai anthropic
- connectors.spec: lookup by openai-codex id (catalog now starts with claude-pro)
- onboarding-model-pool: listProviderModels(provider) helper; label text
  changed to "ChatGPT Plus/Pro (Codex)"
- database integration: added vault insecure-fallback env + electron mock
- command-paths: uses new @main/connector-helpers normalizeCommandValue
- pi-mono-migrations: added `as string` casts for 3 negative-existence
  assertions verifying legacy ids were removed

Drops:
- pnpm-workspace.yaml packages: [] (was "packages/*"; directory empty)
- obsolete CONNECTOR_STRENGTHS import; .module.models probing

Verification:
- pnpm typecheck → 0 errors
- pnpm lint → 0 errors / 0 warnings
- pnpm build:verify → 0 errors / 0 warnings
- pnpm test:unit → 508/508 pass
- pnpm test:integration → 96/96 pass
- All 6 adapter hard gates pass (NOT FOUND / 0 matches / empty)
- pi-ai / pi-agent-core / pi-coding-agent all resolved @0.67.6
This commit is contained in:
ZacharyZhang-NY committed 2026-04-17 02:36:53 -04:00
1 parent 4de9cd0339
commit e94939a562
80 files changed
+2210 -413

No files matched your search

+122
View File
@@ -0,0 +1,122 @@
import type { AppDatabase } from "@main/database";
import type { CredentialBackend, CredentialKind } from "@main/database/credentials";
import type { CredentialStatus } from "@main/database/credentials";
import type { CredentialSummary } from "@shared/contracts/schemas-credentials";
import type { StoredCredentialPayload } from "./types";
const HINT_SUFFIX_LEN = 4;
const HINT_PREFIX_LEN = 6;
function maskApiKey(value: string): string {
if (value.length <= HINT_PREFIX_LEN + HINT_SUFFIX_LEN) {
return `${value.slice(0, 2)}...`;
}
const prefix = value.slice(0, HINT_PREFIX_LEN);
const suffix = value.slice(-HINT_SUFFIX_LEN);
return `${prefix}...${suffix}`;
}
export function deriveDisplayHint(payload: StoredCredentialPayload): string {
switch (payload.kind) {
case "api_key":
return payload.value.source === "literal"
? maskApiKey(payload.value.value)
: `env:${payload.value.value}`;
case "azure":
return payload.value.resourceName
? `azure:${payload.value.resourceName}`
: `azure:${maskApiKey(payload.value.apiKey)}`;
case "aws":
if (payload.value.authMode === "profile") return `aws:profile=${payload.value.awsProfile ?? "?"}`;
if (payload.value.authMode === "iam") return `aws:iam=${maskApiKey(payload.value.accessKeyId ?? "?")}`;
return `aws:bearer`;
case "gcp_adc":
return `gcp:${payload.value.project}@${payload.value.location}`;
case "oauth": {
const expiresMs = payload.value.expires;
const expiresLabel = typeof expiresMs === "number" && Number.isFinite(expiresMs)
? new Date(expiresMs).toISOString()
: "no-expiry";
return `oauth:expires=${expiresLabel}`;
}
}
}
export interface CredentialStoreDeps {
db: AppDatabase;
}
export class CredentialStore {
constructor(private readonly deps: CredentialStoreDeps) {}
list(): CredentialSummary[] {
return this.deps.db.credentialsTable.list().map((row) => ({
connectorId: row.connectorId,
kind: row.kind as CredentialKind,
displayHint: row.displayHint,
status: row.status,
expiresAt: row.expiresAt,
lastRefreshedAt: row.lastRefreshedAt,
lastError: row.lastError,
updatedAt: row.updatedAt,
}));
}
/** Encrypts and stores a credential. Caller is responsible for kind/connectorId match. */
save(connectorId: string, payload: StoredCredentialPayload, expiresAt: string | null = null): CredentialSummary {
const json = JSON.stringify(payload.value);
const { backend, payload: ciphertext } = this.deps.db.vault.encrypt(json);
const stored = this.deps.db.credentialsTable.upsert({
connectorId,
kind: payload.kind,
backend: backend as CredentialBackend,
ciphertext,
displayHint: deriveDisplayHint(payload),
status: "active",
expiresAt,
lastRefreshedAt: null,
lastError: null,
});
return {
connectorId: stored.connectorId,
kind: stored.kind,
displayHint: stored.displayHint,
status: stored.status,
expiresAt: stored.expiresAt,
lastRefreshedAt: stored.lastRefreshedAt,
lastError: stored.lastError,
updatedAt: stored.updatedAt,
};
}
/** Decrypts and returns the typed credential payload. Returns null when missing. */
read(connectorId: string): StoredCredentialPayload | null {
const row = this.deps.db.credentialsTable.get(connectorId);
if (!row) return null;
const json = this.deps.db.vault.decrypt(
row.backend,
Buffer.isBuffer(row.ciphertext) ? row.ciphertext : Buffer.from(row.ciphertext),
);
const value = JSON.parse(json);
return { kind: row.kind, value } as StoredCredentialPayload;
}
remove(connectorId: string): void {
this.deps.db.credentialsTable.remove(connectorId);
}
setStatus(connectorId: string, status: CredentialStatus, lastError: string | null = null): void {
this.deps.db.credentialsTable.setStatus(connectorId, status, lastError);
}
/** Replaces the OAuth ciphertext after a successful refresh. */
saveRefreshedOAuth(connectorId: string, payload: StoredCredentialPayload, expiresAt: string | null): void {
const { backend, payload: ciphertext } = this.deps.db.vault.encrypt(JSON.stringify(payload.value));
this.deps.db.credentialsTable.markRefreshed(
connectorId,
backend as CredentialBackend,
ciphertext,
expiresAt,
);
}
}
+4
View File
@@ -0,0 +1,4 @@
export { CredentialStore, deriveDisplayHint } from "./credential-store";
export { CredentialResolver, CredentialError, type ResolvedCredential } from "./credential-resolver";
export { OAuthLoginService } from "./oauth-login-service";
export type { StoredCredentialPayload, OAuthCredentialPayload, CredentialKind } from "./types";
+30
View File
@@ -0,0 +1,30 @@
import type {
ApiKeyValue,
AwsCredential,
AzureCredential,
GcpAdcCredential,
} from "@shared/contracts/schemas-credentials";
/**
* pi-ai's `OAuthCredentials` shape.
*
* Mirrored locally as a type-only declaration to avoid pulling pi runtime
* symbols into modules that only need the shape. The actual contract is
* enforced by pi at runtime via the OAuth provider interface.
*/
export interface OAuthCredentialPayload {
refresh: string;
access: string;
expires: number;
/** Provider-specific extra fields (e.g. github copilot domain) */
[key: string]: unknown;
}
export type StoredCredentialPayload =
| { kind: "oauth"; value: OAuthCredentialPayload }
| { kind: "api_key"; value: ApiKeyValue }
| { kind: "azure"; value: AzureCredential }
| { kind: "aws"; value: AwsCredential }
| { kind: "gcp_adc"; value: GcpAdcCredential };
export type CredentialKind = StoredCredentialPayload["kind"];