Add biome config and update plugin source + dependencies

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-13 16:54:55 +00:00
parent 284401a4fe
commit bec5d1bf3a
6 changed files with 1138 additions and 878 deletions

View File

@@ -3,227 +3,260 @@
*/
export class LegalApi {
constructor(private baseUrl: string) {}
constructor(private baseUrl: string) {}
private async request<T>(path: string, init?: RequestInit): Promise<T> {
const res = await fetch(`${this.baseUrl}${path}`, {
...init,
headers: {
"Content-Type": "application/json",
...init?.headers,
},
});
if (!res.ok) {
const text = await res.text();
throw new Error(`Legal API ${res.status}: ${text}`);
}
return res.json() as Promise<T>;
}
private async request<T>(path: string, init?: RequestInit): Promise<T> {
const res = await fetch(`${this.baseUrl}${path}`, {
...init,
headers: {
"Content-Type": "application/json",
...init?.headers,
},
});
if (!res.ok) {
const text = await res.text();
throw new Error(`Legal API ${res.status}: ${text}`);
}
return res.json() as Promise<T>;
}
async listCases(): Promise<CaseSummary[]> {
return this.request("/api/cases");
}
async listCases(): Promise<CaseSummary[]> {
return this.request("/api/cases");
}
async getCase(caseNumber: string): Promise<CaseDetails> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/details`);
}
async getCase(caseNumber: string): Promise<CaseDetails> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/details`);
}
async createCase(data: CaseCreateInput): Promise<CaseDetails> {
return this.request("/api/cases/create", {
method: "POST",
body: JSON.stringify(data),
});
}
async createCase(data: CaseCreateInput): Promise<CaseDetails> {
return this.request("/api/cases/create", {
method: "POST",
body: JSON.stringify(data),
});
}
async updateCase(caseNumber: string, data: CaseUpdateInput): Promise<CaseDetails> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}`, {
method: "PUT",
body: JSON.stringify(data),
});
}
async updateCase(
caseNumber: string,
data: CaseUpdateInput,
): Promise<CaseDetails> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}`, {
method: "PUT",
body: JSON.stringify(data),
});
}
async getCaseStatus(caseNumber: string): Promise<WorkflowStatus> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/status`);
}
async getCaseStatus(caseNumber: string): Promise<WorkflowStatus> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/status`);
}
async search(query: string, limit = 10, sectionType = ""): Promise<SearchResult[]> {
const params = new URLSearchParams({ query, limit: String(limit) });
if (sectionType) params.set("section_type", sectionType);
return this.request(`/api/search?${params}`);
}
async search(
query: string,
limit = 10,
sectionType = "",
): Promise<SearchResult[]> {
const params = new URLSearchParams({ query, limit: String(limit) });
if (sectionType) params.set("section_type", sectionType);
return this.request(`/api/search?${params}`);
}
async searchCase(caseNumber: string, query: string, limit = 10): Promise<SearchResult[]> {
const params = new URLSearchParams({ query, limit: String(limit) });
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/search?${params}`);
}
async searchCase(
caseNumber: string,
query: string,
limit = 10,
): Promise<SearchResult[]> {
const params = new URLSearchParams({ query, limit: String(limit) });
return this.request(
`/api/cases/${encodeURIComponent(caseNumber)}/search?${params}`,
);
}
async getTemplate(caseNumber: string): Promise<{ template: string }> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/template`);
}
async getTemplate(caseNumber: string): Promise<{ template: string }> {
return this.request(
`/api/cases/${encodeURIComponent(caseNumber)}/template`,
);
}
async getProcessingStatus(): Promise<ProcessingStatus> {
return this.request("/api/processing-status");
}
async getProcessingStatus(): Promise<ProcessingStatus> {
return this.request("/api/processing-status");
}
async health(): Promise<{ status: string }> {
return this.request("/health");
}
async health(): Promise<{ status: string }> {
return this.request("/health");
}
// ── New methods for expanded workflow ──
// ── New methods for expanded workflow ──
async listDocuments(caseNumber: string): Promise<DocumentInfo[]> {
const details = await this.getCase(caseNumber);
return details.documents || [];
}
async listDocuments(caseNumber: string): Promise<DocumentInfo[]> {
const details = await this.getCase(caseNumber);
return details.documents || [];
}
async getDocumentText(docId: string): Promise<string> {
return this.request(`/api/documents/${docId}/text`);
}
async getDocumentText(docId: string): Promise<string> {
return this.request(`/api/documents/${docId}/text`);
}
async findSimilarCases(caseNumber: string): Promise<SearchResult[]> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/search?query=similar&limit=5`);
}
async findSimilarCases(caseNumber: string): Promise<SearchResult[]> {
return this.request(
`/api/cases/${encodeURIComponent(caseNumber)}/search?query=similar&limit=5`,
);
}
async setOutcome(caseNumber: string, outcome: string, reasoning?: string): Promise<{ status: string }> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/outcome`, {
method: "POST",
body: JSON.stringify({ outcome, reasoning: reasoning || "" }),
});
}
async setOutcome(
caseNumber: string,
outcome: string,
reasoning?: string,
): Promise<{ status: string }> {
return this.request(
`/api/cases/${encodeURIComponent(caseNumber)}/outcome`,
{
method: "POST",
body: JSON.stringify({ outcome, reasoning: reasoning || "" }),
},
);
}
async getClaims(caseNumber: string): Promise<ClaimsResponse> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/claims`);
}
async getClaims(caseNumber: string): Promise<ClaimsResponse> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/claims`);
}
async setDirection(caseNumber: string, directionDoc: Record<string, unknown>): Promise<{ status: string }> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/direction`, {
method: "POST",
body: JSON.stringify({ direction_doc: directionDoc }),
});
}
async setDirection(
caseNumber: string,
directionDoc: Record<string, unknown>,
): Promise<{ status: string }> {
return this.request(
`/api/cases/${encodeURIComponent(caseNumber)}/direction`,
{
method: "POST",
body: JSON.stringify({ direction_doc: directionDoc }),
},
);
}
async runQA(caseNumber: string): Promise<QAResponse> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/qa`, {
method: "POST",
});
}
async runQA(caseNumber: string): Promise<QAResponse> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/qa`, {
method: "POST",
});
}
async triggerLearning(caseNumber: string): Promise<{ status: string }> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/learn`, {
method: "POST",
});
}
async triggerLearning(caseNumber: string): Promise<{ status: string }> {
return this.request(`/api/cases/${encodeURIComponent(caseNumber)}/learn`, {
method: "POST",
});
}
async getStyleGuide(): Promise<string> {
// Return static style guide reference
return "ראה skill-legal-decision/SKILL.md — מדריך סגנון מלא של דפנה תמיר";
}
async getStyleGuide(): Promise<string> {
// Return static style guide reference
return "ראה skill-legal-decision/SKILL.md — מדריך סגנון מלא של דפנה תמיר";
}
}
// Types
export interface CaseSummary {
case_number: string;
title: string;
status: string;
case_number: string;
title: string;
status: string;
}
export interface CaseDetails {
id: string;
case_number: string;
title: string;
status: string;
appellants: string[];
respondents: string[];
subject: string;
property_address: string;
expected_outcome: string;
documents?: DocumentInfo[];
[key: string]: unknown;
id: string;
case_number: string;
title: string;
status: string;
appellants: string[];
respondents: string[];
subject: string;
property_address: string;
expected_outcome: string;
documents?: DocumentInfo[];
[key: string]: unknown;
}
export interface CaseCreateInput {
case_number: string;
title: string;
appellants?: string[];
respondents?: string[];
subject?: string;
property_address?: string;
permit_number?: string;
committee_type?: string;
hearing_date?: string;
notes?: string;
expected_outcome?: string;
case_number: string;
title: string;
appellants?: string[];
respondents?: string[];
subject?: string;
property_address?: string;
permit_number?: string;
committee_type?: string;
hearing_date?: string;
notes?: string;
expected_outcome?: string;
}
export interface CaseUpdateInput {
status?: string;
title?: string;
subject?: string;
notes?: string;
hearing_date?: string;
decision_date?: string;
tags?: string[];
expected_outcome?: string;
status?: string;
title?: string;
subject?: string;
notes?: string;
hearing_date?: string;
decision_date?: string;
tags?: string[];
expected_outcome?: string;
}
export interface DocumentInfo {
id: string;
title: string;
doc_type: string;
extraction_status: string;
page_count?: number;
id: string;
title: string;
doc_type: string;
extraction_status: string;
page_count?: number;
}
export interface WorkflowStatus {
case_number: string;
title: string;
status: string;
documents: Array<{
title: string;
type: string;
extraction: string;
chunks: number;
pages?: number;
}>;
total_documents: number;
total_chunks: number;
has_draft: boolean;
draft_size_bytes: number;
next_steps: string[];
case_number: string;
title: string;
status: string;
documents: Array<{
title: string;
type: string;
extraction: string;
chunks: number;
pages?: number;
}>;
total_documents: number;
total_chunks: number;
has_draft: boolean;
draft_size_bytes: number;
next_steps: string[];
}
export interface SearchResult {
score: number;
case_number?: string;
document: string;
section: string;
page: number;
content: string;
score: number;
case_number?: string;
document: string;
section: string;
page: number;
content: string;
}
export interface ProcessingStatus {
cases: number;
documents: number;
pending_processing: number;
chunks: number;
style_corpus_entries: number;
style_patterns: number;
cases: number;
documents: number;
pending_processing: number;
chunks: number;
style_corpus_entries: number;
style_patterns: number;
}
export interface ClaimsResponse {
case_number: string;
claims: Record<string, Array<{ party_role: string; claim_text: string; claim_index: number }>>;
total: number;
case_number: string;
claims: Record<
string,
Array<{ party_role: string; claim_text: string; claim_index: number }>
>;
total: number;
}
export interface QAResponse {
passed: boolean;
checks: Array<{
check_name: string;
passed: boolean;
severity: string;
details: string;
}>;
status: string;
passed: boolean;
checks: Array<{
check_name: string;
passed: boolean;
severity: string;
details: string;
}>;
status: string;
}

View File

@@ -1,152 +1,161 @@
export default {
id: "marcusgroup.legal-ai",
apiVersion: 1,
version: "0.1.0",
displayName: "Ezer Mishpati - Legal AI",
description:
"Integration with legal decision drafting system — case management, semantic search, and workflow tracking",
author: "Marcus Group",
categories: ["connector"] as const,
capabilities: [
"events.subscribe",
"issues.read",
"issues.create",
"issues.update",
"issue.comments.create",
"agent.tools.register",
"http.outbound",
"plugin.state.read",
"plugin.state.write",
"jobs.schedule",
"activity.log.write",
"companies.read",
"projects.read",
] as const,
entrypoints: {
worker: "dist/worker.js",
},
instanceConfigSchema: {
type: "object" as const,
properties: {
legalApiBaseUrl: {
type: "string" as const,
default: "http://localhost:8085",
description: "Base URL for the Ezer Mishpati API",
},
},
},
tools: [
{
toolKey: "legal_case_list",
name: "legal_case_list",
displayName: "List Legal Cases",
description: "List all appeal cases in the legal system",
parametersSchema: { type: "object" as const, properties: {} },
},
{
toolKey: "legal_case_get",
name: "legal_case_get",
displayName: "Get Legal Case Details",
description: "Get full details of a legal case including documents",
parametersSchema: {
type: "object" as const,
properties: {
case_number: { type: "string" as const, description: "Case number" },
},
required: ["case_number"],
},
},
{
toolKey: "legal_case_create",
name: "legal_case_create",
displayName: "Create Legal Case",
description: "Create a new appeal case with linked Paperclip issue",
parametersSchema: {
type: "object" as const,
properties: {
case_number: { type: "string" as const },
title: { type: "string" as const },
appellants: { type: "array" as const, items: { type: "string" as const } },
respondents: { type: "array" as const, items: { type: "string" as const } },
subject: { type: "string" as const },
property_address: { type: "string" as const },
expected_outcome: { type: "string" as const },
},
required: ["case_number", "title"],
},
},
{
toolKey: "legal_case_update",
name: "legal_case_update",
displayName: "Update Legal Case",
description: "Update a legal case status, title, or outcome",
parametersSchema: {
type: "object" as const,
properties: {
case_number: { type: "string" as const },
status: { type: "string" as const },
title: { type: "string" as const },
expected_outcome: { type: "string" as const },
},
required: ["case_number"],
},
},
{
toolKey: "legal_case_status",
name: "legal_case_status",
displayName: "Get Case Workflow Status",
description: "Get full workflow status: documents, drafts, next steps",
parametersSchema: {
type: "object" as const,
properties: {
case_number: { type: "string" as const },
},
required: ["case_number"],
},
},
{
toolKey: "legal_search",
name: "legal_search",
displayName: "Search Legal Precedents",
description: "Semantic RAG search across previous decisions",
parametersSchema: {
type: "object" as const,
properties: {
query: { type: "string" as const, description: "Search query in Hebrew" },
limit: { type: "number" as const },
section_type: { type: "string" as const },
},
required: ["query"],
},
},
{
toolKey: "legal_case_template",
name: "legal_case_template",
displayName: "Get Decision Template",
description: "Get outcome-aware decision template for 12-block structure",
parametersSchema: {
type: "object" as const,
properties: {
case_number: { type: "string" as const },
},
required: ["case_number"],
},
},
{
toolKey: "legal_processing_status",
name: "legal_processing_status",
displayName: "Get Processing Status",
description: "Get overall system processing status",
parametersSchema: { type: "object" as const, properties: {} },
},
],
jobs: [
{
jobKey: "sync-case-status",
displayName: "Sync Legal Case Status",
description:
"Polls legal-ai for case status changes and updates Paperclip issues",
schedule: "*/15 * * * *",
},
],
id: "marcusgroup.legal-ai",
apiVersion: 1,
version: "0.1.0",
displayName: "Ezer Mishpati - Legal AI",
description:
"Integration with legal decision drafting system — case management, semantic search, and workflow tracking",
author: "Marcus Group",
categories: ["connector"] as const,
capabilities: [
"events.subscribe",
"issues.read",
"issues.create",
"issues.update",
"issue.comments.create",
"agent.tools.register",
"http.outbound",
"plugin.state.read",
"plugin.state.write",
"jobs.schedule",
"activity.log.write",
"companies.read",
"projects.read",
] as const,
entrypoints: {
worker: "dist/worker.js",
},
instanceConfigSchema: {
type: "object" as const,
properties: {
legalApiBaseUrl: {
type: "string" as const,
default: "http://localhost:8085",
description: "Base URL for the Ezer Mishpati API",
},
},
},
tools: [
{
toolKey: "legal_case_list",
name: "legal_case_list",
displayName: "List Legal Cases",
description: "List all appeal cases in the legal system",
parametersSchema: { type: "object" as const, properties: {} },
},
{
toolKey: "legal_case_get",
name: "legal_case_get",
displayName: "Get Legal Case Details",
description: "Get full details of a legal case including documents",
parametersSchema: {
type: "object" as const,
properties: {
case_number: { type: "string" as const, description: "Case number" },
},
required: ["case_number"],
},
},
{
toolKey: "legal_case_create",
name: "legal_case_create",
displayName: "Create Legal Case",
description: "Create a new appeal case with linked Paperclip issue",
parametersSchema: {
type: "object" as const,
properties: {
case_number: { type: "string" as const },
title: { type: "string" as const },
appellants: {
type: "array" as const,
items: { type: "string" as const },
},
respondents: {
type: "array" as const,
items: { type: "string" as const },
},
subject: { type: "string" as const },
property_address: { type: "string" as const },
expected_outcome: { type: "string" as const },
},
required: ["case_number", "title"],
},
},
{
toolKey: "legal_case_update",
name: "legal_case_update",
displayName: "Update Legal Case",
description: "Update a legal case status, title, or outcome",
parametersSchema: {
type: "object" as const,
properties: {
case_number: { type: "string" as const },
status: { type: "string" as const },
title: { type: "string" as const },
expected_outcome: { type: "string" as const },
},
required: ["case_number"],
},
},
{
toolKey: "legal_case_status",
name: "legal_case_status",
displayName: "Get Case Workflow Status",
description: "Get full workflow status: documents, drafts, next steps",
parametersSchema: {
type: "object" as const,
properties: {
case_number: { type: "string" as const },
},
required: ["case_number"],
},
},
{
toolKey: "legal_search",
name: "legal_search",
displayName: "Search Legal Precedents",
description: "Semantic RAG search across previous decisions",
parametersSchema: {
type: "object" as const,
properties: {
query: {
type: "string" as const,
description: "Search query in Hebrew",
},
limit: { type: "number" as const },
section_type: { type: "string" as const },
},
required: ["query"],
},
},
{
toolKey: "legal_case_template",
name: "legal_case_template",
displayName: "Get Decision Template",
description: "Get outcome-aware decision template for 12-block structure",
parametersSchema: {
type: "object" as const,
properties: {
case_number: { type: "string" as const },
},
required: ["case_number"],
},
},
{
toolKey: "legal_processing_status",
name: "legal_processing_status",
displayName: "Get Processing Status",
description: "Get overall system processing status",
parametersSchema: { type: "object" as const, properties: {} },
},
],
jobs: [
{
jobKey: "sync-case-status",
displayName: "Sync Legal Case Status",
description:
"Polls legal-ai for case status changes and updates Paperclip issues",
schedule: "*/15 * * * *",
},
],
};

File diff suppressed because it is too large Load Diff