@unson/brainbase-mcp 0.23.1 → 0.23.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/company-os-judgment-history.d.ts +157 -0
- package/dist/company-os-judgment-history.js +489 -0
- package/dist/judgment-history-http.d.ts +18 -0
- package/dist/judgment-history-http.js +170 -0
- package/dist/judgment-history.d.ts +178 -0
- package/dist/judgment-history.js +1519 -0
- package/dist/knowledge-continuation.js +1 -1
- package/dist/knowledge-lookup.js +1 -1
- package/dist/local-web-host.d.ts +8 -0
- package/dist/local-web-host.js +36 -0
- package/dist/problem-selection.d.ts +84 -1
- package/dist/problem-selection.js +141 -15
- package/package.json +14 -2
- package/ui/judgment-history.css +173 -0
- package/ui/judgment-history.js +1077 -32
- package/ui/local-web-shell.js +1 -1
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { JUDGMENT_HISTORY_ENTRYPOINTS, createJudgmentHistoryReader, JudgmentHistoryFeedbackConflictError } from './judgment-history.js';
|
|
2
|
+
import { LocalWebHttpError, readJsonObjectBody, writeJson } from './local-web-security.js';
|
|
3
|
+
export const JUDGMENT_HISTORY_HTTP_VERSION = 'judgment-history-http.v1';
|
|
4
|
+
export const JUDGMENT_HISTORY_HTTP_PREFIX = '/api/judgment-history';
|
|
5
|
+
export const JUDGMENT_HISTORY_FEEDBACK_BODY_LIMIT_BYTES = 64 * 1024;
|
|
6
|
+
function methodNotAllowed() {
|
|
7
|
+
const error = new Error('Use GET or POST');
|
|
8
|
+
error.statusCode = 405;
|
|
9
|
+
error.code = 'method_not_allowed';
|
|
10
|
+
return error;
|
|
11
|
+
}
|
|
12
|
+
function matchRoute(pathname, basePath) {
|
|
13
|
+
if (pathname === `${basePath}/home`)
|
|
14
|
+
return { name: 'home' };
|
|
15
|
+
if (pathname === `${basePath}/feedback`)
|
|
16
|
+
return { name: 'feedback' };
|
|
17
|
+
if (!pathname.startsWith(`${basePath}/records/`))
|
|
18
|
+
return null;
|
|
19
|
+
const encoded = pathname.slice(`${basePath}/records/`.length);
|
|
20
|
+
if (!encoded || encoded.includes('/'))
|
|
21
|
+
return null;
|
|
22
|
+
let recordId;
|
|
23
|
+
try {
|
|
24
|
+
recordId = decodeURIComponent(encoded);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
const error = new Error('record_id is not valid percent-encoding');
|
|
28
|
+
error.statusCode = 400;
|
|
29
|
+
error.code = 'invalid_record_id';
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
return { name: 'detail', recordId };
|
|
33
|
+
}
|
|
34
|
+
function queryValue(url, key) {
|
|
35
|
+
const value = url.searchParams.get(key);
|
|
36
|
+
return value === null ? undefined : value;
|
|
37
|
+
}
|
|
38
|
+
function parseLimit(value) {
|
|
39
|
+
if (value === undefined)
|
|
40
|
+
return undefined;
|
|
41
|
+
if (!/^\d+$/u.test(value))
|
|
42
|
+
throw readerError(400, 'invalid_limit', 'limit must be between 1 and 100');
|
|
43
|
+
return Number(value);
|
|
44
|
+
}
|
|
45
|
+
function readerError(statusCode, code, message) {
|
|
46
|
+
const error = new Error(message);
|
|
47
|
+
error.statusCode = statusCode;
|
|
48
|
+
error.code = code;
|
|
49
|
+
return error;
|
|
50
|
+
}
|
|
51
|
+
function parseQuery(url) {
|
|
52
|
+
const allowed = new Set(['period', 'project', 'entrypoint', 'cursor', 'limit']);
|
|
53
|
+
for (const key of url.searchParams.keys()) {
|
|
54
|
+
if (!allowed.has(key))
|
|
55
|
+
throw readerError(400, 'unknown_query', `Unknown query parameter: ${key}`);
|
|
56
|
+
}
|
|
57
|
+
const periodValue = queryValue(url, 'period');
|
|
58
|
+
const period = periodValue === undefined ? undefined : periodValue;
|
|
59
|
+
const entrypointValue = queryValue(url, 'entrypoint');
|
|
60
|
+
const entrypoint = entrypointValue === undefined ? undefined : entrypointValue;
|
|
61
|
+
if (period !== undefined && period !== 'week' && period !== 'past30days' && period !== 'all') {
|
|
62
|
+
throw readerError(400, 'invalid_period', 'period is invalid');
|
|
63
|
+
}
|
|
64
|
+
if (entrypoint !== undefined && !JUDGMENT_HISTORY_ENTRYPOINTS.includes(entrypoint)) {
|
|
65
|
+
throw readerError(400, 'invalid_entrypoint', 'entrypoint is invalid');
|
|
66
|
+
}
|
|
67
|
+
const project = queryValue(url, 'project');
|
|
68
|
+
const cursor = queryValue(url, 'cursor');
|
|
69
|
+
const limit = parseLimit(queryValue(url, 'limit'));
|
|
70
|
+
return {
|
|
71
|
+
...(period === undefined ? {} : { period }),
|
|
72
|
+
...(project === undefined ? {} : { project }),
|
|
73
|
+
...(entrypoint === undefined ? {} : { entrypoint }),
|
|
74
|
+
...(cursor === undefined ? {} : { cursor }),
|
|
75
|
+
...(limit === undefined ? {} : { limit })
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function toError(error) {
|
|
79
|
+
if (error && typeof error === 'object'
|
|
80
|
+
&& typeof error.statusCode === 'number'
|
|
81
|
+
&& typeof error.code === 'string') {
|
|
82
|
+
return error;
|
|
83
|
+
}
|
|
84
|
+
return readerError(500, 'judgment_history_failed', error instanceof Error ? error.message : 'Judgment history read failed');
|
|
85
|
+
}
|
|
86
|
+
/** Node-style GET route for the common normal-judgment history contract. */
|
|
87
|
+
export function createJudgmentHistoryHttpHandler(options) {
|
|
88
|
+
if (!options?.reader || typeof options.reader.home !== 'function' || typeof options.reader.detail !== 'function') {
|
|
89
|
+
throw new TypeError('reader is required');
|
|
90
|
+
}
|
|
91
|
+
const basePath = (options.basePath ?? JUDGMENT_HISTORY_HTTP_PREFIX).replace(/\/+$/u, '');
|
|
92
|
+
const reader = options.reader;
|
|
93
|
+
return async (request, response) => {
|
|
94
|
+
const url = new URL(request.url ?? '/', 'http://localhost');
|
|
95
|
+
let route;
|
|
96
|
+
try {
|
|
97
|
+
route = matchRoute(url.pathname, basePath);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
const normalized = toError(error);
|
|
101
|
+
writeJson(response, normalized.statusCode, {
|
|
102
|
+
error: { code: normalized.code, message: normalized.message }
|
|
103
|
+
});
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
if (!route)
|
|
107
|
+
return false;
|
|
108
|
+
try {
|
|
109
|
+
if (route.name === 'feedback') {
|
|
110
|
+
if (request.method !== 'POST')
|
|
111
|
+
throw methodNotAllowed();
|
|
112
|
+
if (!options.assertWriteAllowed) {
|
|
113
|
+
throw new LocalWebHttpError(403, 'feedback_write_unconfigured', 'Feedback writes are not configured for this host');
|
|
114
|
+
}
|
|
115
|
+
if (!options.writeFeedback) {
|
|
116
|
+
throw new LocalWebHttpError(503, 'feedback_write_unavailable', 'Feedback writes are unavailable');
|
|
117
|
+
}
|
|
118
|
+
await options.assertWriteAllowed(request);
|
|
119
|
+
const input = await readJsonObjectBody(request, JUDGMENT_HISTORY_FEEDBACK_BODY_LIMIT_BYTES);
|
|
120
|
+
const result = await options.writeFeedback(input);
|
|
121
|
+
const responseBody = {
|
|
122
|
+
status: result.status,
|
|
123
|
+
saved: true,
|
|
124
|
+
created: result.created,
|
|
125
|
+
feedback_event: result.event,
|
|
126
|
+
...result.event
|
|
127
|
+
};
|
|
128
|
+
writeJson(response, result.created ? 201 : 200, responseBody);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
if (request.method !== 'GET')
|
|
132
|
+
throw methodNotAllowed();
|
|
133
|
+
if (route.name === 'home') {
|
|
134
|
+
writeJson(response, 200, await reader.home(parseQuery(url)));
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
const result = await reader.detail(route.recordId);
|
|
138
|
+
if (result.status === 'unavailable') {
|
|
139
|
+
writeJson(response, 200, result);
|
|
140
|
+
}
|
|
141
|
+
else if (result.status === 'available' && !result.record) {
|
|
142
|
+
throw readerError(404, 'judgment_history_not_found', 'No judgment history record matches this id');
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
writeJson(response, 200, result);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
const normalized = toError(error);
|
|
152
|
+
if (error instanceof JudgmentHistoryFeedbackConflictError) {
|
|
153
|
+
writeJson(response, normalized.statusCode, {
|
|
154
|
+
error: { code: normalized.code, message: normalized.message },
|
|
155
|
+
feedback_event: error.existing
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
writeJson(response, normalized.statusCode, {
|
|
160
|
+
error: { code: normalized.code, message: normalized.message }
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return true;
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/** Convenience composition seam for adapters that want the HTTP contract without a local journal. */
|
|
168
|
+
export function createJudgmentHistoryHttpReader(options) {
|
|
169
|
+
return createJudgmentHistoryReader(options);
|
|
170
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/** Public normal-judgment history contract. Value-proof records use a separate contract. */
|
|
2
|
+
export declare const JUDGMENT_HISTORY_RECORD_SCHEMA: "brainbase-judgment-history-record-v1";
|
|
3
|
+
export declare const JUDGMENT_HISTORY_CONTRACT_VERSION: "brainbase.judgment-history.v1";
|
|
4
|
+
export declare const JUDGMENT_HISTORY_FEEDBACK_SCHEMA: "brainbase-judgment-history-feedback-v1";
|
|
5
|
+
export declare const JUDGMENT_HISTORY_ENTRYPOINTS: readonly ["codex", "claude_code", "mana", "company_os", "unknown"];
|
|
6
|
+
export type JudgmentHistoryEntrypoint = typeof JUDGMENT_HISTORY_ENTRYPOINTS[number];
|
|
7
|
+
export type JudgmentHistoryStatus = 'available' | 'partial' | 'unavailable';
|
|
8
|
+
export type JudgmentHistoryStorage = 'local' | 'server';
|
|
9
|
+
export type JudgmentHistoryPeriod = 'week' | 'past30days' | 'all';
|
|
10
|
+
export type JudgmentHistoryReferenceAvailability = 'recorded' | 'permission_denied' | 'unavailable' | 'unknown';
|
|
11
|
+
export type JudgmentHistoryExecutionStatus = 'pending' | 'completed' | 'failed' | 'held' | 'cancelled' | 'unknown';
|
|
12
|
+
export type JudgmentHistoryOutcomeStatus = 'unconfirmed' | 'confirmed' | 'unknown';
|
|
13
|
+
export type JudgmentHistoryFeedbackKind = 'feedback' | 'result' | 'correction';
|
|
14
|
+
export interface JudgmentHistoryFeedbackContent {
|
|
15
|
+
readonly summary: string;
|
|
16
|
+
readonly outcome_status?: JudgmentHistoryOutcomeStatus;
|
|
17
|
+
}
|
|
18
|
+
/** Public feedback event. Storage timestamps and digests are deliberately omitted. */
|
|
19
|
+
export interface JudgmentHistoryFeedbackEvent {
|
|
20
|
+
readonly record_id: string;
|
|
21
|
+
readonly event_id: string;
|
|
22
|
+
readonly kind: JudgmentHistoryFeedbackKind;
|
|
23
|
+
readonly content: JudgmentHistoryFeedbackContent;
|
|
24
|
+
}
|
|
25
|
+
export interface JudgmentHistoryFeedbackWriteResult {
|
|
26
|
+
readonly event: JudgmentHistoryFeedbackEvent;
|
|
27
|
+
readonly created: boolean;
|
|
28
|
+
readonly status: 'saved' | 'already_saved';
|
|
29
|
+
}
|
|
30
|
+
export interface JudgmentHistoryReference {
|
|
31
|
+
readonly ref: string;
|
|
32
|
+
readonly kind: string | null;
|
|
33
|
+
readonly version: string | null;
|
|
34
|
+
readonly digest: string | null;
|
|
35
|
+
readonly why: string | null;
|
|
36
|
+
readonly usage: string | null;
|
|
37
|
+
readonly availability: JudgmentHistoryReferenceAvailability;
|
|
38
|
+
}
|
|
39
|
+
export interface JudgmentHistoryAlternative {
|
|
40
|
+
readonly label: string;
|
|
41
|
+
readonly evaluation: string | null;
|
|
42
|
+
readonly adopted: boolean | null;
|
|
43
|
+
}
|
|
44
|
+
export interface JudgmentHistoryJudgment {
|
|
45
|
+
readonly status: 'resolved' | 'needs_clarification' | 'unknown';
|
|
46
|
+
readonly summary: string | null;
|
|
47
|
+
readonly reason: string | null;
|
|
48
|
+
readonly selected_references: readonly JudgmentHistoryReference[] | null;
|
|
49
|
+
readonly alternatives: readonly JudgmentHistoryAlternative[] | null;
|
|
50
|
+
}
|
|
51
|
+
export interface JudgmentHistoryExecution {
|
|
52
|
+
readonly status: JudgmentHistoryExecutionStatus;
|
|
53
|
+
readonly result_summary: string | null;
|
|
54
|
+
readonly outcome_status: JudgmentHistoryOutcomeStatus;
|
|
55
|
+
}
|
|
56
|
+
export interface JudgmentHistoryRecord {
|
|
57
|
+
readonly schema_version: typeof JUDGMENT_HISTORY_RECORD_SCHEMA;
|
|
58
|
+
readonly record_id: string;
|
|
59
|
+
readonly entrypoint: JudgmentHistoryEntrypoint;
|
|
60
|
+
readonly recorded_at: string;
|
|
61
|
+
readonly project_code: string | null;
|
|
62
|
+
readonly turn_ref: string;
|
|
63
|
+
readonly judgment: JudgmentHistoryJudgment;
|
|
64
|
+
readonly execution: JudgmentHistoryExecution;
|
|
65
|
+
readonly missing_fields: readonly string[];
|
|
66
|
+
/** Append-only result/correction events linked to this normal record. */
|
|
67
|
+
readonly feedback_events?: readonly JudgmentHistoryFeedbackEvent[];
|
|
68
|
+
}
|
|
69
|
+
export interface JudgmentHistorySourceInfo {
|
|
70
|
+
readonly entrypoint: JudgmentHistoryEntrypoint;
|
|
71
|
+
readonly status: JudgmentHistoryStatus;
|
|
72
|
+
readonly reason: string | null;
|
|
73
|
+
}
|
|
74
|
+
export interface JudgmentHistoryCoverage {
|
|
75
|
+
readonly complete: boolean;
|
|
76
|
+
readonly storage: JudgmentHistoryStorage;
|
|
77
|
+
readonly reason: string | null;
|
|
78
|
+
readonly sources: readonly JudgmentHistorySourceInfo[];
|
|
79
|
+
/** Null means the adapter cannot prove the total under this scope/filter. */
|
|
80
|
+
readonly total: number | null;
|
|
81
|
+
}
|
|
82
|
+
export interface JudgmentHistorySourceSnapshot {
|
|
83
|
+
readonly status: JudgmentHistoryStatus;
|
|
84
|
+
readonly records: readonly JudgmentHistoryRecord[] | null;
|
|
85
|
+
readonly coverage: JudgmentHistoryCoverage;
|
|
86
|
+
/** Stable source revision used to bind pagination cursors. */
|
|
87
|
+
readonly snapshot_id?: string;
|
|
88
|
+
}
|
|
89
|
+
export interface JudgmentHistorySource {
|
|
90
|
+
readonly storage: JudgmentHistoryStorage;
|
|
91
|
+
readonly read: () => Promise<JudgmentHistorySourceSnapshot>;
|
|
92
|
+
}
|
|
93
|
+
export interface JudgmentHistoryQuery {
|
|
94
|
+
readonly period?: JudgmentHistoryPeriod;
|
|
95
|
+
readonly project?: string;
|
|
96
|
+
readonly entrypoint?: JudgmentHistoryEntrypoint;
|
|
97
|
+
readonly cursor?: string;
|
|
98
|
+
readonly limit?: number;
|
|
99
|
+
}
|
|
100
|
+
export interface JudgmentHistoryFilters {
|
|
101
|
+
readonly period: JudgmentHistoryPeriod;
|
|
102
|
+
readonly project: string | null;
|
|
103
|
+
readonly entrypoint: JudgmentHistoryEntrypoint | null;
|
|
104
|
+
}
|
|
105
|
+
export interface JudgmentHistoryPagination {
|
|
106
|
+
readonly cursor: string | null;
|
|
107
|
+
readonly next_cursor: string | null;
|
|
108
|
+
readonly limit: number;
|
|
109
|
+
readonly has_more: boolean;
|
|
110
|
+
}
|
|
111
|
+
export interface JudgmentHistoryHome {
|
|
112
|
+
readonly contract_version: typeof JUDGMENT_HISTORY_CONTRACT_VERSION;
|
|
113
|
+
readonly status: JudgmentHistoryStatus;
|
|
114
|
+
readonly records: readonly JudgmentHistoryRecord[] | null;
|
|
115
|
+
readonly coverage: JudgmentHistoryCoverage;
|
|
116
|
+
readonly pagination: JudgmentHistoryPagination;
|
|
117
|
+
readonly filters: JudgmentHistoryFilters;
|
|
118
|
+
}
|
|
119
|
+
export interface JudgmentHistoryDetail {
|
|
120
|
+
readonly contract_version: typeof JUDGMENT_HISTORY_CONTRACT_VERSION;
|
|
121
|
+
readonly status: JudgmentHistoryStatus;
|
|
122
|
+
readonly record: JudgmentHistoryRecord | null;
|
|
123
|
+
readonly coverage: JudgmentHistoryCoverage;
|
|
124
|
+
}
|
|
125
|
+
export interface JudgmentHistoryReaderOptions {
|
|
126
|
+
readonly source: JudgmentHistorySource;
|
|
127
|
+
readonly now?: () => Date;
|
|
128
|
+
/** Organization adapters provide trusted scope authorization here. */
|
|
129
|
+
readonly authorizeProject?: (project: string) => boolean | Promise<boolean>;
|
|
130
|
+
}
|
|
131
|
+
export interface JudgmentHistoryReader {
|
|
132
|
+
readonly home: (query?: JudgmentHistoryQuery) => Promise<JudgmentHistoryHome>;
|
|
133
|
+
readonly detail: (recordId: string) => Promise<JudgmentHistoryDetail>;
|
|
134
|
+
}
|
|
135
|
+
export declare class JudgmentHistoryReaderError extends Error {
|
|
136
|
+
readonly statusCode: number;
|
|
137
|
+
readonly code: string;
|
|
138
|
+
constructor(statusCode: number, code: string, message: string);
|
|
139
|
+
}
|
|
140
|
+
export interface LocalJudgmentHistorySourceOptions {
|
|
141
|
+
readonly root: string;
|
|
142
|
+
readonly entrypoint?: JudgmentHistoryEntrypoint;
|
|
143
|
+
/** Maximum number of candidate journal files inspected in one read. */
|
|
144
|
+
readonly max_files?: number;
|
|
145
|
+
/** Maximum size of one journal artifact, in bytes. */
|
|
146
|
+
readonly max_record_bytes?: number;
|
|
147
|
+
}
|
|
148
|
+
export interface LocalJudgmentHistoryFeedbackWriterOptions {
|
|
149
|
+
readonly root: string;
|
|
150
|
+
readonly reader: JudgmentHistoryReader;
|
|
151
|
+
readonly now?: () => Date;
|
|
152
|
+
}
|
|
153
|
+
export type JudgmentHistoryFeedbackWriter = (input: unknown) => Promise<JudgmentHistoryFeedbackWriteResult>;
|
|
154
|
+
export declare class JudgmentHistoryFeedbackError extends Error {
|
|
155
|
+
readonly statusCode: number;
|
|
156
|
+
readonly code: string;
|
|
157
|
+
constructor(statusCode: number, code: string, message: string);
|
|
158
|
+
}
|
|
159
|
+
export declare class JudgmentHistoryFeedbackConflictError extends JudgmentHistoryFeedbackError {
|
|
160
|
+
readonly existing: JudgmentHistoryFeedbackEvent;
|
|
161
|
+
constructor(existing: JudgmentHistoryFeedbackEvent);
|
|
162
|
+
}
|
|
163
|
+
export declare const DEFAULT_LOCAL_JUDGMENT_HISTORY_SCAN_CAP = 4096;
|
|
164
|
+
export declare const DEFAULT_LOCAL_JUDGMENT_HISTORY_RECORD_BYTES: number;
|
|
165
|
+
export declare function canonicalJson(value: unknown): string;
|
|
166
|
+
/** Reads only the configured local owner journal; it never searches or uploads another journal. */
|
|
167
|
+
export declare function createLocalJudgmentHistorySource(options: LocalJudgmentHistorySourceOptions): JudgmentHistorySource;
|
|
168
|
+
/**
|
|
169
|
+
* Append-only local feedback writer for normal judgment records. It writes a
|
|
170
|
+
* separate immutable event file below the configured journal and always
|
|
171
|
+
* confirms the event through the same reader before returning success.
|
|
172
|
+
*/
|
|
173
|
+
export declare function createLocalJudgmentHistoryFeedbackWriter(options: LocalJudgmentHistoryFeedbackWriterOptions): JudgmentHistoryFeedbackWriter;
|
|
174
|
+
export declare function appendLocalJudgmentHistoryFeedback(options: LocalJudgmentHistoryFeedbackWriterOptions & {
|
|
175
|
+
readonly input: unknown;
|
|
176
|
+
}): Promise<JudgmentHistoryFeedbackWriteResult>;
|
|
177
|
+
/** Reader shared by local, organization, Mana, and Company OS adapters. */
|
|
178
|
+
export declare function createJudgmentHistoryReader(options: JudgmentHistoryReaderOptions): JudgmentHistoryReader;
|