Add full shell, replaceable Omics adapter and bilingual interaction
Implement approved specification #32 and tickets #33-#37. Keep host authentication server-verified and pin session interaction language. Compile scoped base selectors for browser compatibility and retain full gutters during CSS pruning.
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
import { Type } from "typebox";
|
||||
import { installRepairGate } from "./repair.js";
|
||||
|
||||
// Compatibility note: reviewer labels move verbatim from the composition root.
|
||||
// Tickets #22 and #23 require observable parity; translating existing chrome is a
|
||||
// separate product behavior change rather than part of these extractions.
|
||||
// The composition root supplies manifest language; only deterministic chrome is localized.
|
||||
|
||||
function normalizedText(value) {
|
||||
return String(value ?? "").trim().replace(/\s+/g, " ").toLowerCase();
|
||||
@@ -31,7 +29,7 @@ function memoryOptionKey(option) {
|
||||
}
|
||||
|
||||
|
||||
function normalizeMemoryOptions(options) {
|
||||
function normalizeMemoryOptions(options, locale, gateText) {
|
||||
const seen = new Set();
|
||||
const out = [];
|
||||
for (const option of options) {
|
||||
@@ -47,7 +45,7 @@ function normalizeMemoryOptions(options) {
|
||||
].join(" ").match(MEMORY_ID_RE)?.[0]?.toLowerCase();
|
||||
const fallbackDetail = [
|
||||
option.decision?.type && option.decision?.subject
|
||||
? `Decisione ${option.decision.type}: ${option.decision.subject}`
|
||||
? `${gateText(locale, "decision")} ${option.decision.type}: ${option.decision.subject}`
|
||||
: "",
|
||||
option.decision?.detail ?? "",
|
||||
].filter(Boolean).join("\n");
|
||||
@@ -62,12 +60,15 @@ function normalizeMemoryOptions(options) {
|
||||
}
|
||||
|
||||
|
||||
function memorySelectionWidgetProps(options) {
|
||||
function memorySelectionWidgetProps(options, locale, gateText) {
|
||||
return {
|
||||
title: "Seleziona le memory da applicare alla domanda",
|
||||
title: gateText(locale, "memoryTitle"),
|
||||
titleI18n: gateText("en", "memoryTitle"),
|
||||
selected: options.filter((option) => option.recommended).map((option) => option.id),
|
||||
selectionLabel: "memory da applicare",
|
||||
confirmLabel: "Applica le memory selezionate",
|
||||
selectionLabel: gateText(locale, "memorySelection"),
|
||||
confirmLabel: gateText(locale, "memoryApply"),
|
||||
selectionLabelI18n: gateText("en", "memorySelection"),
|
||||
confirmLabelI18n: gateText("en", "memoryApply"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -78,10 +79,11 @@ function shouldSkipEmptyRecall({ meritCount, allowEmpty, advance }) {
|
||||
|
||||
|
||||
async function reviewRecall(ctx, params, phase, dependencies) {
|
||||
const { workflow, ledger, reviewer, waitForReviewer, toTextResult } = dependencies;
|
||||
const { workflow, ledger, reviewer, waitForReviewer, toTextResult, languageFor, gateText } = dependencies;
|
||||
try {
|
||||
const { session, advance } = params;
|
||||
const options = normalizeMemoryOptions(params.options);
|
||||
const locale = languageFor(ctx, session);
|
||||
const options = normalizeMemoryOptions(params.options, locale, gateText);
|
||||
const typeError = ledger.validate(ctx, options, session);
|
||||
if (typeError) return toTextResult(typeError);
|
||||
const meritOptions = options
|
||||
@@ -99,7 +101,7 @@ async function reviewRecall(ctx, params, phase, dependencies) {
|
||||
advance,
|
||||
})) {
|
||||
await ctx.ui.notify(
|
||||
"Nessuna memory riutilizzabile per questa domanda — passo alla fase successiva.",
|
||||
gateText(locale, "memoryEmpty"),
|
||||
"info",
|
||||
);
|
||||
workflow.advance(ctx, session);
|
||||
@@ -113,7 +115,7 @@ async function reviewRecall(ctx, params, phase, dependencies) {
|
||||
phase,
|
||||
allowEmpty: params.allow_empty ?? false,
|
||||
options: meritOptions,
|
||||
...memorySelectionWidgetProps(options),
|
||||
...memorySelectionWidgetProps(options, locale, gateText),
|
||||
});
|
||||
const response = await waitForReviewer(ctx, widget);
|
||||
if (response.control === "freetext") {
|
||||
@@ -161,7 +163,7 @@ async function reviewRecall(ctx, params, phase, dependencies) {
|
||||
}
|
||||
|
||||
|
||||
function installMemoryGate(pi, { workflow, memory, ledger, waitForReviewer, toTextResult }) {
|
||||
function installMemoryGate(pi, { workflow, memory, ledger, waitForReviewer, toTextResult, languageFor, gateText }) {
|
||||
pi.registerTool({
|
||||
name: "reviewer_memory_promote",
|
||||
label: "Review Memory summary",
|
||||
@@ -188,7 +190,8 @@ function installMemoryGate(pi, { workflow, memory, ledger, waitForReviewer, toTe
|
||||
}
|
||||
const response = await waitForReviewer(ctx, {
|
||||
id: `u${Date.now()}`, schema_version: 1, phase: phase.id,
|
||||
widget: "memory-review", title: "Memory for future questions",
|
||||
widget: "memory-review", title: gateText(languageFor(ctx, session), "memorySummary"),
|
||||
title_i18n: gateText("en", "memorySummary"),
|
||||
summary, reserved: ["other", "back", "exit"],
|
||||
});
|
||||
if (response.control) return toTextResult(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Type } from "typebox";
|
||||
|
||||
export function installRepairGate(pi, { workflow, memory, waitForReviewer, toTextResult }) {
|
||||
export function installRepairGate(pi, { workflow, memory, waitForReviewer, toTextResult, languageFor, gateText }) {
|
||||
pi.registerTool({
|
||||
name: "reviewer_archive_repair",
|
||||
label: "Resolve Memory / Evidence conflict",
|
||||
@@ -26,6 +26,7 @@ export function installRepairGate(pi, { workflow, memory, waitForReviewer, toTex
|
||||
try {
|
||||
if (!!params.repair_id === !!params.proposal)
|
||||
return toTextResult("Supply either a new proposal or an existing repair_id.");
|
||||
const locale = languageFor(ctx, params.session);
|
||||
const run = args => JSON.parse(memory.execute(ctx,
|
||||
[...args, "--session", params.session, "--json"]));
|
||||
let repair = params.repair_id
|
||||
@@ -36,7 +37,9 @@ export function installRepairGate(pi, { workflow, memory, waitForReviewer, toTex
|
||||
const response = await waitForReviewer(ctx, {
|
||||
id: `u${Date.now()}`, schema_version: 1,
|
||||
phase: workflow.phase(ctx, params.session).id,
|
||||
widget: "archive-repair", title: "Resolve archive conflict",
|
||||
widget: "archive-repair", title: gateText(locale, "archiveRepair"),
|
||||
title_i18n: gateText("en", "archiveRepair"),
|
||||
...(error ? { error_i18n: gateText("en", "repairError") } : {}),
|
||||
repair, error, reserved: ["other", "back", "exit"],
|
||||
});
|
||||
if (response.control) return toTextResult(response.control === "freetext"
|
||||
@@ -62,7 +65,7 @@ export function installRepairGate(pi, { workflow, memory, waitForReviewer, toTex
|
||||
return toTextResult("All repair proposals were rejected as inadequate. " +
|
||||
"No archive was changed. Reformulate the options for the reviewer.");
|
||||
} catch (failure) {
|
||||
error = "The correction could not complete. Review the current archive state before retrying.";
|
||||
error = gateText(locale, "repairError");
|
||||
repair = run(["repair-show", "--repair-id", repair.repair_id]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user