|
1 | 1 | import assert from "node:assert/strict"; |
2 | 2 | import { readFileSync } from "node:fs"; |
3 | | -import { goalCreateRequest } from "./goal-create-request.ts"; |
| 3 | +import { goalCreateRequest, goalCreationAgentId } from "./goal-create-request.ts"; |
4 | 4 | import { localizedCapabilityFieldCopy } from "./capability-localization.ts"; |
5 | 5 | import { taskSessionStatus } from "./goal-activity.ts"; |
6 | 6 | import "./monitor-readback.test.mjs"; |
7 | 7 |
|
8 | 8 | const source = (name) => readFileSync(new URL(name, import.meta.url), "utf8"); |
| 9 | +const projectionAgent = { agentId: "status-only", adapterKind: "status_projection", available: true, label: "Status" }; |
| 10 | +const missingAgent = { agentId: "codex", available: false, label: "Codex" }; |
| 11 | +const availableAgent = { agentId: "claude", available: true, label: "Claude" }; |
| 12 | +assert.equal(goalCreationAgentId("status-only", [missingAgent, projectionAgent]), "codex", "Creation diagnoses the real missing executor, never the read-only snapshot"); |
| 13 | +assert.equal(goalCreationAgentId("status-only", [missingAgent, availableAgent, projectionAgent]), "claude", "Creation can use the discovered available executor"); |
| 14 | +assert.equal(goalCreationAgentId("codex", [missingAgent, availableAgent, projectionAgent]), "codex", "An explicit unavailable executor remains selected for its own gate"); |
| 15 | +assert.equal(goalCreationAgentId("custom", [missingAgent, projectionAgent]), "custom", "An unknown explicit identity is left for backend eligibility"); |
| 16 | +assert.equal(goalCreationAgentId("status-only", [projectionAgent]), "status-only", "An empty executor catalog cannot manufacture an executor"); |
9 | 17 | const answerText = source("./answer-text.ts"); |
10 | 18 | const model = source("./personal-workspace-model.ts"); |
11 | 19 | const activity = source("./goal-activity.ts"); |
@@ -693,3 +701,13 @@ for (const route of ["./views/frontstage-developer-page", "./views/benchmark-stu |
693 | 701 | assert.equal((page.match(/<Suspense fallback=\{<p className="personal-lazy-loading" role="status">/g) ?? []).length, 1, "The lazy settings site shows a loading status"); |
694 | 702 |
|
695 | 703 | console.log("personal workspace drawer contract smoke passed"); |
| 704 | + |
| 705 | +// An unavailable first Agent: the service refuses the creation preview with a |
| 706 | +// typed gate (kind, agent, catalog reason) and the page tells the owner in |
| 707 | +// their language, never with the protocol sentence; nothing is written. |
| 708 | +assert.match(page, /const agentGate = gateKind === "agent_unavailable"/, "The page maps the typed Agent gate to owner-language copy"); |
| 709 | +assert.match(page, /reasonCode === "executable_not_found"[\s\S]*?reasonCode === "api_key_not_set"[\s\S]*?rawGate\.registered === false/, "The reason follows the catalog's own fields"); |
| 710 | +assert.match(source("./context-drawer.tsx"), /selection\.item\.gate\?\.kind === "agent_unavailable" \? selection\.item\.title/, "The drawer shows the Agent gate's own title, not host confirmation"); |
| 711 | +for (const key of ["proposal.agentGate.title", "proposal.agentGate.summary", "proposal.agentGate.reason.executable_not_found", "proposal.agentGate.reason.api_key_not_set", "proposal.agentGate.reason.unregistered", "proposal.agentGate.reason.unavailable", "proposal.agentGate.nextAction", "proposal.agentGate.impact"]) { |
| 712 | + assert.equal((i18n.match(new RegExp(`"${key.replace(/\./g, "\\.")}":`, "g")) ?? []).length, 2, `${key} exists in both locales`); |
| 713 | +} |
0 commit comments