fb3f1df13e
- Remove all learnship references: Decision.learnship_equivalent field,
agent persona prompts, opencode.json permissions, test fixtures
- Migrate verification layers from .planning/ to .ci/: structural
checks .ci/ dir + ROADMAP.md, behavioral checks ROADMAP.md
- Fix ollama-local: remove sync require+curl blocking, use async
fetchAvailableModels() in callModel
- Fix opencode.json: use __OPENCODE_DIR__ template tokens, remove
legacy learnship permission entries
- Remove duplicate install script from package.json (keep postinstall)
- Fix quality any-regex false positives (target type annotations only)
- Add backends test coverage: backends.test.ts, tool-registry.test.ts
- Version bump 0.3.0 → 0.4.0
- Artifacts module: rename .planning→.ci internal paths
- Remove dead TODO_PATTERN/FIXME_PATTERN constants
---ci---
phase: 3
milestone: v0.4
status: complete
requirements:
covered: [REQ-09, REQ-10, REQ-11, REQ-13, REQ-14, REQ-17]
partial: []
decisions:
- id: D-001
decision: purge all learnship references from codebase
rationale: project is CI-only, learnship is no longer a dependency
confidence: 0.99
category: scope
alternatives: [keep for historical reference]
- id: D-002
decision: migrate verification from .planning/ to .ci/ paths
rationale: .planning/ is removed schema, all current state lives in .ci/
confidence: 0.95
category: architecture
alternatives: [keep dual-path support]
- id: D-003
decision: use __OPENCODE_DIR__ template tokens in opencode.json
rationale: hardcoded ~ paths fail in containers and non-standard homes
confidence: 0.90
category: implementation_approach
alternatives: [keep tilde expansion]
---/ci---
129 lines
4.1 KiB
TypeScript
129 lines
4.1 KiB
TypeScript
import { BackendUnavailableError, emptyTokenUsage, emptyBackendResult, DEFAULT_BACKEND_CONFIG } from "../backends/types.js";
|
|
import { OllamaLocalBackend } from "../backends/ollama-local.js";
|
|
import { OllamaCloudBackend } from "../backends/ollama-cloud.js";
|
|
import { OpencodeBackend } from "../backends/opencode.js";
|
|
|
|
describe("BackendUnavailableError", () => {
|
|
it("includes backend name in message", () => {
|
|
const err = new BackendUnavailableError("ollama-local");
|
|
expect(err.message).toContain("ollama-local");
|
|
expect(err.backendName).toBe("ollama-local");
|
|
});
|
|
|
|
it("includes agent name when provided", () => {
|
|
const err = new BackendUnavailableError("opencode", "executor");
|
|
expect(err.agentName).toBe("executor");
|
|
expect(err.message).toContain("executor");
|
|
});
|
|
});
|
|
|
|
describe("emptyTokenUsage", () => {
|
|
it("returns zeroed usage", () => {
|
|
const usage = emptyTokenUsage();
|
|
expect(usage.input_tokens).toBe(0);
|
|
expect(usage.output_tokens).toBe(0);
|
|
expect(usage.total_tokens).toBe(0);
|
|
expect(usage.estimated_cost_usd).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("emptyBackendResult", () => {
|
|
it("returns failed result with no artifacts", () => {
|
|
const result = emptyBackendResult("something failed");
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toBe("something failed");
|
|
expect(result.artifacts).toEqual([]);
|
|
expect(result.decisions).toEqual([]);
|
|
expect(result.escalations).toEqual([]);
|
|
});
|
|
|
|
it("returns result without error when no message provided", () => {
|
|
const result = emptyBackendResult();
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("DEFAULT_BACKEND_CONFIG", () => {
|
|
it("has auto provider by default", () => {
|
|
expect(DEFAULT_BACKEND_CONFIG.provider).toBe("auto");
|
|
});
|
|
|
|
it("has opencode agent backend enabled", () => {
|
|
expect(DEFAULT_BACKEND_CONFIG.agent_backends.opencode?.enabled).toBe(true);
|
|
});
|
|
|
|
it("has ollama-local and ollama-cloud llm backends", () => {
|
|
expect(DEFAULT_BACKEND_CONFIG.llm_backends["ollama-local"]).toBeDefined();
|
|
expect(DEFAULT_BACKEND_CONFIG.llm_backends["ollama-cloud"]).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe("OllamaLocalBackend", () => {
|
|
it("has correct name and type", () => {
|
|
const backend = new OllamaLocalBackend();
|
|
expect(backend.name).toBe("ollama-local");
|
|
expect(backend.type).toBe("llm");
|
|
});
|
|
|
|
it("returns false when local Ollama is not available", async () => {
|
|
const backend = new OllamaLocalBackend({
|
|
base_url: "http://localhost:1",
|
|
model_profile: "balanced",
|
|
});
|
|
const available = await backend.isAvailable();
|
|
expect(available).toBe(false);
|
|
});
|
|
|
|
it("uses default config when none provided", () => {
|
|
const backend = new OllamaLocalBackend();
|
|
expect(backend).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe("OllamaCloudBackend", () => {
|
|
it("has correct name and type", () => {
|
|
const backend = new OllamaCloudBackend();
|
|
expect(backend.name).toBe("ollama-cloud");
|
|
expect(backend.type).toBe("llm");
|
|
});
|
|
|
|
it("returns false when no base_url configured", async () => {
|
|
const backend = new OllamaCloudBackend({
|
|
base_url: "",
|
|
api_key_env: "NONEXISTENT_KEY",
|
|
model_profile: "quality",
|
|
timeout_ms: 5000,
|
|
});
|
|
const available = await backend.isAvailable();
|
|
expect(available).toBe(false);
|
|
});
|
|
|
|
it("returns false when no API key available", async () => {
|
|
const backend = new OllamaCloudBackend({
|
|
base_url: "https://example.com",
|
|
api_key_env: "NONEXISTENT_CI_KEY_12345",
|
|
model_profile: "quality",
|
|
timeout_ms: 5000,
|
|
});
|
|
const available = await backend.isAvailable();
|
|
expect(available).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("OpencodeBackend", () => {
|
|
it("has correct name and type", () => {
|
|
const backend = new OpencodeBackend();
|
|
expect(backend.name).toBe("opencode");
|
|
expect(backend.type).toBe("agent");
|
|
});
|
|
|
|
it("returns false when opencode is not installed", async () => {
|
|
const backend = new OpencodeBackend({
|
|
enabled: true,
|
|
executable: "nonexistent-opencode-binary-xyz",
|
|
});
|
|
const available = await backend.isAvailable();
|
|
expect(available).toBe(false);
|
|
});
|
|
}); |