shortcut registry keyed (96 -> 73)
shortcuts.ts is data with no component around it, so it carries catalog keys and ShortcutsModal resolves them -- same shape as the settings sections. gen-platform-skill.ts also reads this registry to generate the agent-facing SKILL.md, which docs:check validates. That doc stays in one language, so the generator resolves against en-GB directly and throws if a key is missing rather than emitting a dot-path into a file an agent will quote at somebody. The regenerated skill is byte-identical, which is the check that keying the registry changed nothing an agent reads.
This commit is contained in:
@@ -38,6 +38,16 @@ const KIND_MEANING: Record<string, string> = {
|
||||
export async function renderPlatformSkill(): Promise<string> {
|
||||
const { PERMISSIONS } = await import('../src/servers/permissions/registry');
|
||||
const { SHORTCUT_SECTIONS } = await import('../src/apps/officer-web/state/shortcuts');
|
||||
const enCatalog = (await import('../src/apps/officer-web/locales/en-GB.json')).default as Record<string, unknown>;
|
||||
/** Resolve a dot-path against the English catalog. This doc is for agents and stays in one language. */
|
||||
const enString = (key: string): string => {
|
||||
const value = key.split('.').reduce<unknown>((node, part) => {
|
||||
if (node && typeof node === 'object') return (node as Record<string, unknown>)[part];
|
||||
return undefined;
|
||||
}, enCatalog);
|
||||
if (typeof value !== 'string') throw new Error(`gen-platform-skill: no English string for "${key}"`);
|
||||
return value;
|
||||
};
|
||||
|
||||
const byKind = new Map<string, typeof PERMISSIONS>();
|
||||
for (const p of PERMISSIONS) {
|
||||
@@ -112,14 +122,16 @@ export async function renderPlatformSkill(): Promise<string> {
|
||||
out('Derived from `src/apps/officer-web/state/shortcuts.ts`. These have moved several times; quote this');
|
||||
out('list rather than remembering one.');
|
||||
out();
|
||||
// The registry holds catalog keys since the shell was localized; this doc is agent-facing and stays
|
||||
// English, so it resolves against en-GB rather than the reader's locale.
|
||||
for (const section of SHORTCUT_SECTIONS) {
|
||||
out(`## ${section.title}`);
|
||||
if (section.note) {
|
||||
out(`## ${enString(section.titleKey)}`);
|
||||
if (section.noteKey) {
|
||||
out();
|
||||
out(section.note);
|
||||
out(enString(section.noteKey));
|
||||
}
|
||||
out();
|
||||
for (const s of section.shortcuts) out(`- \`${s.keys}\` — ${s.description}`);
|
||||
for (const s of section.shortcuts) out(`- \`${s.keys}\` — ${enString(s.descriptionKey)}`);
|
||||
out();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user