feat(cli): add terminal-UI i18n runtime and upgrade Ink to 7 (U6)
Add a synchronous Node-side i18next instance built from the generated @fusion/i18n CLI catalog map (no async backend, first frame localized), with locale precedence --lang flag -> GlobalSettings.language -> env (LC_ALL/LANG/..) -> en. Wrap the Ink DashboardApp render in <I18nextProvider> and thread a --lang flag through runDashboard. Upgrade ink 6.8 -> 7.0 (native CJK double-width measurement) and raise the react/@types/react peer floor to ^19.2.0. A spike test confirms react-i18next works under Ink's custom reconciler: localized first frame + re-render on changeLanguage (including CJK), retiring the KTD1 unknown. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -60,13 +60,13 @@
|
||||
"dockerode": "^4.0.12",
|
||||
"express": "^5.1.0",
|
||||
"i18next": "^26.3.1",
|
||||
"ink": "^6.8.0",
|
||||
"ink": "^7.0.5",
|
||||
"ink-spinner": "^5.0.0",
|
||||
"ink-text-input": "^6.0.0",
|
||||
"ioredis": "^5.6.0",
|
||||
"multer": "^2.1.1",
|
||||
"node-pty": "npm:@homebridge/node-pty-prebuilt-multiarch@^0.13.1",
|
||||
"react": "^19.0.0",
|
||||
"react": "^19.2.0",
|
||||
"react-i18next": "^17.0.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -93,7 +93,7 @@
|
||||
"@fusion/pi-claude-cli": "workspace:*",
|
||||
"@fusion/pi-llama-cpp": "workspace:*",
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react": "^19.2.0",
|
||||
"@vitest/coverage-v8": "^3.1.0",
|
||||
"cross-env": "^7.0.0",
|
||||
"esbuild": "^0.25.12",
|
||||
|
||||
@@ -733,7 +733,9 @@ async function main() {
|
||||
const noAuth = args.includes("--no-auth");
|
||||
const dashTokenIdx = args.indexOf("--token");
|
||||
const token = dashTokenIdx !== -1 && dashTokenIdx + 1 < args.length ? args[dashTokenIdx + 1] : undefined;
|
||||
await runDashboard(port, { paused, dev, interactive, host, noAuth, token });
|
||||
const dashLangIdx = args.indexOf("--lang");
|
||||
const lang = dashLangIdx !== -1 && dashLangIdx + 1 < args.length ? args[dashLangIdx + 1] : undefined;
|
||||
await runDashboard(port, { paused, dev, interactive, host, noAuth, token, lang });
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -157,6 +157,9 @@ export class DashboardTUI {
|
||||
// will reapply the auto policy.
|
||||
mouseEnabled: boolean = false;
|
||||
|
||||
// Optional `--lang` override; highest-precedence locale source for the TUI.
|
||||
lang?: string;
|
||||
|
||||
constructor() {
|
||||
this.logBuffer = new LogRingBuffer();
|
||||
}
|
||||
@@ -669,6 +672,20 @@ export class DashboardTUI {
|
||||
const { render } = await import("ink");
|
||||
const { createElement } = await import("react");
|
||||
const { DashboardApp } = await import("./app.js");
|
||||
const { I18nextProvider } = await import("react-i18next");
|
||||
const { initCliI18n, resolveCliLocale } = await import("../../i18n/index.js");
|
||||
const { GlobalSettingsStore } = await import("@fusion/core");
|
||||
|
||||
// Resolve locale: --lang flag → persisted GlobalSettings → env → en.
|
||||
let settingLanguage: string | undefined;
|
||||
try {
|
||||
settingLanguage = (await new GlobalSettingsStore().getSettings())?.language;
|
||||
} catch {
|
||||
// Settings unreadable — fall back to env/default.
|
||||
}
|
||||
const i18n = initCliI18n(
|
||||
resolveCliLocale({ flag: this.lang, setting: settingLanguage, env: process.env }),
|
||||
);
|
||||
|
||||
// Enter the terminal's alternate-screen buffer before mounting Ink so
|
||||
// the TUI gets a dedicated fullscreen surface that doesn't share
|
||||
@@ -683,7 +700,7 @@ export class DashboardTUI {
|
||||
}
|
||||
|
||||
this.inkInstance = render(
|
||||
createElement(DashboardApp, { controller: this }),
|
||||
createElement(I18nextProvider, { i18n }, createElement(DashboardApp, { controller: this })),
|
||||
);
|
||||
|
||||
// Mouse mode must be enabled AFTER Ink mounts (which calls
|
||||
|
||||
@@ -686,7 +686,7 @@ async function resolveDashboardAuthToken(opts: { noAuth?: boolean; token?: strin
|
||||
return tokenManager.generateToken();
|
||||
}
|
||||
|
||||
export async function runDashboard(port: number, opts: { paused?: boolean; dev?: boolean; interactive?: boolean; open?: boolean; host?: string; noAuth?: boolean; token?: string } = {}) {
|
||||
export async function runDashboard(port: number, opts: { paused?: boolean; dev?: boolean; interactive?: boolean; open?: boolean; host?: string; noAuth?: boolean; token?: string; lang?: string } = {}) {
|
||||
// Default to localhost so the dashboard (and its shell-capable terminal API)
|
||||
// is not exposed on the LAN. Pass --host 0.0.0.0 explicitly to opt-in.
|
||||
const selectedHost = opts.host ?? "127.0.0.1";
|
||||
@@ -752,6 +752,7 @@ export async function runDashboard(port: number, opts: { paused?: boolean; dev?:
|
||||
|
||||
if (isTTY) {
|
||||
tui = new DashboardTUI();
|
||||
tui.lang = opts.lang;
|
||||
void startupUpdateStatusPromise.then((updateStatus) => {
|
||||
tui?.setUpdateStatus(updateStatus);
|
||||
});
|
||||
|
||||
69
packages/cli/src/i18n/__tests__/i18n.test.tsx
Normal file
69
packages/cli/src/i18n/__tests__/i18n.test.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Text } from "ink";
|
||||
import { render } from "ink-testing-library";
|
||||
import { createElement } from "react";
|
||||
import { I18nextProvider, useTranslation } from "react-i18next";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { cliI18n, detectEnvLocale, initCliI18n, resolveCliLocale } from "../index.js";
|
||||
|
||||
describe("detectEnvLocale", () => {
|
||||
it("parses POSIX locale env values to a supported locale", () => {
|
||||
expect(detectEnvLocale({ LANG: "fr_FR.UTF-8" })).toBe("fr");
|
||||
expect(detectEnvLocale({ LC_ALL: "es_ES.UTF-8" })).toBe("es");
|
||||
expect(detectEnvLocale({ LANG: "zh_CN.UTF-8" })).toBe("zh-CN");
|
||||
expect(detectEnvLocale({ LANG: "zh_TW" })).toBe("zh-TW");
|
||||
});
|
||||
|
||||
it("honors precedence LC_ALL > LC_MESSAGES > LANG > LANGUAGE", () => {
|
||||
expect(detectEnvLocale({ LC_ALL: "fr_FR", LANG: "es_ES" })).toBe("fr");
|
||||
expect(detectEnvLocale({ LC_MESSAGES: "es_ES", LANG: "fr_FR" })).toBe("es");
|
||||
});
|
||||
|
||||
it("falls back to a bare language and undefined for unsupported", () => {
|
||||
expect(detectEnvLocale({ LANG: "zh" })).toBe("zh-CN");
|
||||
expect(detectEnvLocale({ LANG: "de_DE.UTF-8" })).toBeUndefined();
|
||||
expect(detectEnvLocale({})).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveCliLocale precedence", () => {
|
||||
it("flag overrides setting and env", () => {
|
||||
expect(resolveCliLocale({ flag: "zh-TW", setting: "fr", env: { LANG: "es_ES" } })).toBe("zh-TW");
|
||||
});
|
||||
it("setting overrides env", () => {
|
||||
expect(resolveCliLocale({ setting: "fr", env: { LANG: "es_ES" } })).toBe("fr");
|
||||
});
|
||||
it("env used when no flag/setting", () => {
|
||||
expect(resolveCliLocale({ env: { LANG: "es_ES.UTF-8" } })).toBe("es");
|
||||
});
|
||||
it("defaults to en", () => {
|
||||
expect(resolveCliLocale({ env: {} })).toBe("en");
|
||||
expect(resolveCliLocale({ flag: "de", env: {} })).toBe("en");
|
||||
});
|
||||
});
|
||||
|
||||
// The load-bearing spike: react-i18next must work under Ink's custom reconciler.
|
||||
function Loading() {
|
||||
const { t } = useTranslation("cli");
|
||||
return createElement(Text, null, t("tui.loading", "Loading…"));
|
||||
}
|
||||
|
||||
describe("react-i18next under the Ink reconciler", () => {
|
||||
it("renders a localized first frame synchronously", () => {
|
||||
const i18n = initCliI18n("en");
|
||||
const { lastFrame } = render(
|
||||
createElement(I18nextProvider, { i18n }, createElement(Loading)),
|
||||
);
|
||||
expect(lastFrame()).toContain("Loading…");
|
||||
});
|
||||
|
||||
it("re-renders on changeLanguage", async () => {
|
||||
const i18n = initCliI18n("en");
|
||||
cliI18n.addResourceBundle("zh-CN", "cli", { tui: { loading: "加载中…" } }, true, true);
|
||||
const { lastFrame } = render(
|
||||
createElement(I18nextProvider, { i18n }, createElement(Loading)),
|
||||
);
|
||||
expect(lastFrame()).toContain("Loading…");
|
||||
await i18n.changeLanguage("zh-CN");
|
||||
expect(lastFrame()).toContain("加载中…");
|
||||
});
|
||||
});
|
||||
78
packages/cli/src/i18n/index.ts
Normal file
78
packages/cli/src/i18n/index.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { DEFAULT_LOCALE, isLocale, type Locale } from "@fusion/core";
|
||||
import {
|
||||
baseInitOptions,
|
||||
CLI_NAMESPACES,
|
||||
cliResources,
|
||||
DEFAULT_NAMESPACE,
|
||||
} from "@fusion/i18n";
|
||||
import i18next, { type i18n as I18nInstance, type Resource } from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
|
||||
/**
|
||||
* Terminal-UI i18next instance.
|
||||
*
|
||||
* Unlike the dashboard, the CLI bundles all catalogs statically (via the
|
||||
* generated @fusion/i18n cli map) and initializes synchronously (inline
|
||||
* resources, no async backend) so the very first rendered Ink frame is
|
||||
* already localized — no flash of untranslated keys.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parse a POSIX locale environment value (e.g. `fr_FR.UTF-8`, `zh_CN`,
|
||||
* `zh-Hant`) into a supported {@link Locale}, or undefined when none matches.
|
||||
*/
|
||||
export function detectEnvLocale(env: NodeJS.ProcessEnv = process.env): Locale | undefined {
|
||||
const raw = env.LC_ALL || env.LC_MESSAGES || env.LANG || env.LANGUAGE;
|
||||
if (!raw) return undefined;
|
||||
|
||||
// Strip encoding/modifier (`.UTF-8`, `@euro`) and normalize `_` to `-`.
|
||||
const code = raw.split(/[.:@\s]/)[0].replace("_", "-");
|
||||
if (isLocale(code)) return code;
|
||||
|
||||
const lang = code.split("-")[0].toLowerCase();
|
||||
if (isLocale(lang)) return lang;
|
||||
// A bare `zh` resolves to Simplified, mirroring the shared fallback chain.
|
||||
if (lang === "zh") return "zh-CN";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the active CLI locale with precedence:
|
||||
* `--lang flag → persisted GlobalSettings.language → environment → en`.
|
||||
*/
|
||||
export function resolveCliLocale(opts: {
|
||||
flag?: string | undefined;
|
||||
setting?: string | undefined;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
} = {}): Locale {
|
||||
const { flag, setting, env = process.env } = opts;
|
||||
if (isLocale(flag)) return flag;
|
||||
if (isLocale(setting)) return setting;
|
||||
return detectEnvLocale(env) ?? DEFAULT_LOCALE;
|
||||
}
|
||||
|
||||
let initialized = false;
|
||||
|
||||
/** Initialize (synchronously) or switch the CLI i18next instance to `locale`. */
|
||||
export function initCliI18n(locale: Locale): I18nInstance {
|
||||
if (!initialized) {
|
||||
void i18next.use(initReactI18next).init({
|
||||
...baseInitOptions(),
|
||||
lng: locale,
|
||||
ns: [...CLI_NAMESPACES],
|
||||
defaultNS: DEFAULT_NAMESPACE,
|
||||
// Inline resources + no async backend => init completes synchronously,
|
||||
// so the first rendered Ink frame is already localized (i18next v26
|
||||
// dropped the old `initImmediate` flag; this is now the default for
|
||||
// backend-less, resource-inlined init).
|
||||
resources: cliResources as unknown as Resource,
|
||||
react: { useSuspense: false },
|
||||
});
|
||||
initialized = true;
|
||||
} else if (i18next.language !== locale) {
|
||||
void i18next.changeLanguage(locale);
|
||||
}
|
||||
return i18next;
|
||||
}
|
||||
|
||||
export { i18next as cliI18n };
|
||||
179
pnpm-lock.yaml
generated
179
pnpm-lock.yaml
generated
@@ -46,10 +46,10 @@ importers:
|
||||
dependencies:
|
||||
'@earendil-works/pi-ai':
|
||||
specifier: ^0.78.0
|
||||
version: 0.78.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)
|
||||
version: 0.78.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)
|
||||
'@earendil-works/pi-coding-agent':
|
||||
specifier: ^0.78.0
|
||||
version: 0.78.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)
|
||||
version: 0.78.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)
|
||||
dockerode:
|
||||
specifier: ^4.0.12
|
||||
version: 4.0.12
|
||||
@@ -60,14 +60,14 @@ importers:
|
||||
specifier: ^26.3.1
|
||||
version: 26.3.1(typescript@5.9.3)
|
||||
ink:
|
||||
specifier: ^6.8.0
|
||||
version: 6.8.0(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4)
|
||||
specifier: ^7.0.5
|
||||
version: 7.0.5(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4)
|
||||
ink-spinner:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0(ink@6.8.0(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4))(react@19.2.4)
|
||||
version: 5.0.0(ink@7.0.5(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4))(react@19.2.4)
|
||||
ink-text-input:
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0(ink@6.8.0(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4))(react@19.2.4)
|
||||
version: 6.0.0(ink@7.0.5(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4))(react@19.2.4)
|
||||
ioredis:
|
||||
specifier: ^5.6.0
|
||||
version: 5.10.1
|
||||
@@ -78,7 +78,7 @@ importers:
|
||||
specifier: npm:@homebridge/node-pty-prebuilt-multiarch@^0.13.1
|
||||
version: '@homebridge/node-pty-prebuilt-multiarch@0.13.1'
|
||||
react:
|
||||
specifier: ^19.0.0
|
||||
specifier: ^19.2.0
|
||||
version: 19.2.4
|
||||
react-i18next:
|
||||
specifier: ^17.0.8
|
||||
@@ -106,7 +106,7 @@ importers:
|
||||
specifier: ^25.5.2
|
||||
version: 25.5.2
|
||||
'@types/react':
|
||||
specifier: ^19.0.0
|
||||
specifier: ^19.2.0
|
||||
version: 19.2.14
|
||||
'@vitest/coverage-v8':
|
||||
specifier: ^3.1.0
|
||||
@@ -562,10 +562,10 @@ importers:
|
||||
dependencies:
|
||||
'@earendil-works/pi-ai':
|
||||
specifier: '*'
|
||||
version: 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)
|
||||
version: 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-coding-agent':
|
||||
specifier: '*'
|
||||
version: 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)
|
||||
version: 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^25.5.2
|
||||
@@ -1017,8 +1017,8 @@ packages:
|
||||
'@adobe/css-tools@4.4.4':
|
||||
resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==}
|
||||
|
||||
'@alcalzone/ansi-tokenize@0.2.5':
|
||||
resolution: {integrity: sha512-3NX/MpTdroi0aKz134A6RC2Gb2iXVECN4QaAXnvCIxxIm3C3AVB1mkUe8NaaiyvOpDfsrqWhYtj+Q6a62RrTsw==}
|
||||
'@alcalzone/ansi-tokenize@0.3.0':
|
||||
resolution: {integrity: sha512-p+CMKJ93HFmLkjXKlXiVGlMQEuRb6H0MokBSwUsX+S6BRX8eV5naFZpQJFfJHjRZY0Hmnqy1/r6UWl3x+19zYA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@ampproject/remapping@2.3.0':
|
||||
@@ -3550,9 +3550,9 @@ packages:
|
||||
resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
cli-boxes@3.0.0:
|
||||
resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
|
||||
engines: {node: '>=10'}
|
||||
cli-boxes@4.0.1:
|
||||
resolution: {integrity: sha512-5IOn+jcCEHEraYolBPs/sT4BxYCe2nHg374OPiItB1O96KZFseS2gthU4twyYzeDcFew4DaUM/xwc5BQf08JJw==}
|
||||
engines: {node: '>=18.20 <19 || >=20.10'}
|
||||
|
||||
cli-cursor@3.1.0:
|
||||
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
|
||||
@@ -3578,9 +3578,9 @@ packages:
|
||||
resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
cli-truncate@5.2.0:
|
||||
resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==}
|
||||
engines: {node: '>=20'}
|
||||
cli-truncate@6.0.0:
|
||||
resolution: {integrity: sha512-3+YKIUFsohD9MIoOFPFBldjAlnfCmCDcqe6aYGFqlDTRKg80p4wg35L+j83QQ63iOlKRccEkbn8IuM++HsgEjA==}
|
||||
engines: {node: '>=22'}
|
||||
|
||||
cli-width@4.1.0:
|
||||
resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
|
||||
@@ -3943,9 +3943,6 @@ packages:
|
||||
resolution: {integrity: sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
||||
emoji-regex@10.6.0:
|
||||
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
|
||||
|
||||
emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
|
||||
@@ -4616,12 +4613,12 @@ packages:
|
||||
ink: '>=5'
|
||||
react: '>=18'
|
||||
|
||||
ink@6.8.0:
|
||||
resolution: {integrity: sha512-sbl1RdLOgkO9isK42WCZlJCFN9hb++sX9dsklOvfd1YQ3bQ2AiFu12Q6tFlr0HvEUvzraJntQCCpfEoUe9DSzA==}
|
||||
engines: {node: '>=20'}
|
||||
ink@7.0.5:
|
||||
resolution: {integrity: sha512-zWNjGHQPxSeiSAmDUOq+QPQ6CfmMhmNi85vrJIuy4prafKKUSoZlXEy4wbM7LuLuF1pDURk7qvF4fxrQlLxv3w==}
|
||||
engines: {node: '>=22'}
|
||||
peerDependencies:
|
||||
'@types/react': '>=19.0.0'
|
||||
react: '>=19.0.0'
|
||||
'@types/react': '>=19.2.0'
|
||||
react: '>=19.2.0'
|
||||
react-devtools-core: '>=6.1.2'
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
@@ -6134,9 +6131,9 @@ packages:
|
||||
resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
slice-ansi@8.0.0:
|
||||
resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==}
|
||||
engines: {node: '>=20'}
|
||||
slice-ansi@9.0.0:
|
||||
resolution: {integrity: sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA==}
|
||||
engines: {node: '>=22'}
|
||||
|
||||
smart-buffer@4.2.0:
|
||||
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
|
||||
@@ -6235,10 +6232,6 @@ packages:
|
||||
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
string-width@7.2.0:
|
||||
resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
string-width@8.2.0:
|
||||
resolution: {integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==}
|
||||
engines: {node: '>=20'}
|
||||
@@ -6767,6 +6760,10 @@ packages:
|
||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
wrap-ansi@10.0.0:
|
||||
resolution: {integrity: sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -6779,10 +6776,6 @@ packages:
|
||||
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
wrap-ansi@9.0.2:
|
||||
resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
wrappy@1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
|
||||
@@ -6916,7 +6909,7 @@ snapshots:
|
||||
|
||||
'@adobe/css-tools@4.4.4': {}
|
||||
|
||||
'@alcalzone/ansi-tokenize@0.2.5':
|
||||
'@alcalzone/ansi-tokenize@0.3.0':
|
||||
dependencies:
|
||||
ansi-styles: 6.2.3
|
||||
is-fullwidth-code-point: 5.1.0
|
||||
@@ -7650,9 +7643,9 @@ snapshots:
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@earendil-works/pi-agent-core@0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)':
|
||||
'@earendil-works/pi-agent-core@0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@earendil-works/pi-ai': 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)
|
||||
'@earendil-works/pi-ai': 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)
|
||||
ignore: 7.0.5
|
||||
typebox: 1.1.38
|
||||
yaml: 2.9.0
|
||||
@@ -7664,9 +7657,9 @@ snapshots:
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@earendil-works/pi-agent-core@0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)':
|
||||
'@earendil-works/pi-agent-core@0.78.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)':
|
||||
dependencies:
|
||||
'@earendil-works/pi-ai': 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-ai': 0.78.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)
|
||||
ignore: 7.0.5
|
||||
typebox: 1.1.38
|
||||
yaml: 2.9.0
|
||||
@@ -7726,26 +7719,6 @@ snapshots:
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@earendil-works/pi-ai@0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)':
|
||||
dependencies:
|
||||
'@anthropic-ai/sdk': 0.91.1(zod@3.25.76)
|
||||
'@aws-sdk/client-bedrock-runtime': 3.1048.0
|
||||
'@google/genai': 1.52.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))
|
||||
'@mistralai/mistralai': 2.2.1
|
||||
'@smithy/node-http-handler': 4.7.3
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.6
|
||||
openai: 6.26.0(ws@8.20.0)(zod@3.25.76)
|
||||
partial-json: 0.1.7
|
||||
typebox: 1.1.38
|
||||
transitivePeerDependencies:
|
||||
- '@modelcontextprotocol/sdk'
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@earendil-works/pi-ai@0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@anthropic-ai/sdk': 0.91.1(zod@4.3.6)
|
||||
@@ -7766,6 +7739,26 @@ snapshots:
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@earendil-works/pi-ai@0.78.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)':
|
||||
dependencies:
|
||||
'@anthropic-ai/sdk': 0.91.1(zod@3.25.76)
|
||||
'@aws-sdk/client-bedrock-runtime': 3.1048.0
|
||||
'@google/genai': 1.52.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))
|
||||
'@mistralai/mistralai': 2.2.1
|
||||
'@smithy/node-http-handler': 4.7.3
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.6
|
||||
openai: 6.26.0(ws@8.20.0)(zod@3.25.76)
|
||||
partial-json: 0.1.7
|
||||
typebox: 1.1.38
|
||||
transitivePeerDependencies:
|
||||
- '@modelcontextprotocol/sdk'
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@earendil-works/pi-ai@0.78.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@anthropic-ai/sdk': 0.91.1(zod@4.3.6)
|
||||
@@ -7835,10 +7828,10 @@ snapshots:
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@earendil-works/pi-coding-agent@0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)':
|
||||
'@earendil-works/pi-coding-agent@0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@earendil-works/pi-agent-core': 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)
|
||||
'@earendil-works/pi-ai': 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)
|
||||
'@earendil-works/pi-agent-core': 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-ai': 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-tui': 0.77.0
|
||||
'@silvia-odwyer/photon-node': 0.3.4
|
||||
chalk: 5.6.2
|
||||
@@ -7864,11 +7857,11 @@ snapshots:
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@earendil-works/pi-coding-agent@0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)':
|
||||
'@earendil-works/pi-coding-agent@0.78.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)':
|
||||
dependencies:
|
||||
'@earendil-works/pi-agent-core': 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-ai': 0.77.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-tui': 0.77.0
|
||||
'@earendil-works/pi-agent-core': 0.78.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)
|
||||
'@earendil-works/pi-ai': 0.78.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)
|
||||
'@earendil-works/pi-tui': 0.78.0
|
||||
'@silvia-odwyer/photon-node': 0.3.4
|
||||
chalk: 5.6.2
|
||||
cross-spawn: 7.0.6
|
||||
@@ -10106,7 +10099,7 @@ snapshots:
|
||||
|
||||
ci-info@4.4.0: {}
|
||||
|
||||
cli-boxes@3.0.0: {}
|
||||
cli-boxes@4.0.1: {}
|
||||
|
||||
cli-cursor@3.1.0:
|
||||
dependencies:
|
||||
@@ -10130,9 +10123,9 @@ snapshots:
|
||||
string-width: 4.2.3
|
||||
optional: true
|
||||
|
||||
cli-truncate@5.2.0:
|
||||
cli-truncate@6.0.0:
|
||||
dependencies:
|
||||
slice-ansi: 8.0.0
|
||||
slice-ansi: 9.0.0
|
||||
string-width: 8.2.0
|
||||
|
||||
cli-width@4.1.0: {}
|
||||
@@ -10529,8 +10522,6 @@ snapshots:
|
||||
dependencies:
|
||||
sax: 1.1.4
|
||||
|
||||
emoji-regex@10.6.0: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
|
||||
emoji-regex@9.2.2: {}
|
||||
@@ -11351,33 +11342,33 @@ snapshots:
|
||||
|
||||
ini@4.1.3: {}
|
||||
|
||||
ink-spinner@5.0.0(ink@6.8.0(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4))(react@19.2.4):
|
||||
ink-spinner@5.0.0(ink@7.0.5(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4))(react@19.2.4):
|
||||
dependencies:
|
||||
cli-spinners: 2.9.2
|
||||
ink: 6.8.0(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4)
|
||||
ink: 7.0.5(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4)
|
||||
react: 19.2.4
|
||||
|
||||
ink-testing-library@4.0.0(@types/react@19.2.14):
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.14
|
||||
|
||||
ink-text-input@6.0.0(ink@6.8.0(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4))(react@19.2.4):
|
||||
ink-text-input@6.0.0(ink@7.0.5(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4))(react@19.2.4):
|
||||
dependencies:
|
||||
chalk: 5.6.2
|
||||
ink: 6.8.0(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4)
|
||||
ink: 7.0.5(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4)
|
||||
react: 19.2.4
|
||||
type-fest: 4.41.0
|
||||
|
||||
ink@6.8.0(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4):
|
||||
ink@7.0.5(@types/react@19.2.14)(react-devtools-core@7.0.1)(react@19.2.4):
|
||||
dependencies:
|
||||
'@alcalzone/ansi-tokenize': 0.2.5
|
||||
'@alcalzone/ansi-tokenize': 0.3.0
|
||||
ansi-escapes: 7.3.0
|
||||
ansi-styles: 6.2.3
|
||||
auto-bind: 5.0.1
|
||||
chalk: 5.6.2
|
||||
cli-boxes: 3.0.0
|
||||
cli-boxes: 4.0.1
|
||||
cli-cursor: 4.0.0
|
||||
cli-truncate: 5.2.0
|
||||
cli-truncate: 6.0.0
|
||||
code-excerpt: 4.0.0
|
||||
es-toolkit: 1.45.1
|
||||
indent-string: 5.0.0
|
||||
@@ -11387,13 +11378,13 @@ snapshots:
|
||||
react-reconciler: 0.33.0(react@19.2.4)
|
||||
scheduler: 0.27.0
|
||||
signal-exit: 3.0.7
|
||||
slice-ansi: 8.0.0
|
||||
slice-ansi: 9.0.0
|
||||
stack-utils: 2.0.6
|
||||
string-width: 8.2.0
|
||||
terminal-size: 4.0.1
|
||||
type-fest: 5.5.0
|
||||
widest-line: 6.0.0
|
||||
wrap-ansi: 9.0.2
|
||||
wrap-ansi: 10.0.0
|
||||
ws: 8.20.0
|
||||
yoga-layout: 3.2.1
|
||||
optionalDependencies:
|
||||
@@ -13205,7 +13196,7 @@ snapshots:
|
||||
astral-regex: 2.0.0
|
||||
is-fullwidth-code-point: 3.0.0
|
||||
|
||||
slice-ansi@8.0.0:
|
||||
slice-ansi@9.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.3
|
||||
is-fullwidth-code-point: 5.1.0
|
||||
@@ -13307,12 +13298,6 @@ snapshots:
|
||||
emoji-regex: 9.2.2
|
||||
strip-ansi: 7.2.0
|
||||
|
||||
string-width@7.2.0:
|
||||
dependencies:
|
||||
emoji-regex: 10.6.0
|
||||
get-east-asian-width: 1.6.0
|
||||
strip-ansi: 7.2.0
|
||||
|
||||
string-width@8.2.0:
|
||||
dependencies:
|
||||
get-east-asian-width: 1.6.0
|
||||
@@ -13945,6 +13930,12 @@ snapshots:
|
||||
|
||||
word-wrap@1.2.5: {}
|
||||
|
||||
wrap-ansi@10.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.3
|
||||
string-width: 8.2.0
|
||||
strip-ansi: 7.2.0
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
@@ -13963,12 +13954,6 @@ snapshots:
|
||||
string-width: 5.1.2
|
||||
strip-ansi: 7.2.0
|
||||
|
||||
wrap-ansi@9.0.2:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.3
|
||||
string-width: 7.2.0
|
||||
strip-ansi: 7.2.0
|
||||
|
||||
wrappy@1.0.2: {}
|
||||
|
||||
ws@7.5.10: {}
|
||||
|
||||
Reference in New Issue
Block a user