@json-to-office/jto 2.4.0 → 3.0.0
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/cli.js +123 -39
- package/dist/cli.js.map +1 -1
- package/dist/client/assets/HomePage-BlzZ7qG4.js +245 -0
- package/dist/client/assets/HomePage-BlzZ7qG4.js.map +1 -0
- package/dist/client/assets/{JsonEditorPage-DjLAUBv5.js → JsonEditorPage-kWuP_kL3.js} +3 -3
- package/dist/client/assets/{JsonEditorPage-DjLAUBv5.js.map → JsonEditorPage-kWuP_kL3.js.map} +1 -1
- package/dist/client/assets/{MonacoPluginProvider-D_GUFwWQ.js → MonacoPluginProvider-Dbv1PrO2.js} +6 -6
- package/dist/client/assets/{MonacoPluginProvider-D_GUFwWQ.js.map → MonacoPluginProvider-Dbv1PrO2.js.map} +1 -1
- package/dist/client/assets/{_virtual_jto-plugin-type-libs-9elxvZT2.js → _virtual_jto-plugin-type-libs-B6KyD9RL.js} +9182 -4529
- package/dist/client/assets/{_virtual_jto-plugin-type-libs-9elxvZT2.js.map → _virtual_jto-plugin-type-libs-B6KyD9RL.js.map} +1 -1
- package/dist/client/assets/_virtual_jto-sandbox-runtime-Bzo2M5U7.js +2 -0
- package/dist/client/assets/_virtual_jto-sandbox-runtime-Bzo2M5U7.js.map +1 -0
- package/dist/client/assets/editor-CwEocOY2.js +16 -0
- package/dist/client/assets/editor-CwEocOY2.js.map +1 -0
- package/dist/client/assets/editor-monaco-json-D_oiidNg.js +24 -0
- package/dist/client/assets/editor-monaco-json-D_oiidNg.js.map +1 -0
- package/dist/client/assets/index--kF4jVbp.css +1 -0
- package/dist/client/assets/index-DFJaEoi0.js +27 -0
- package/dist/client/assets/index-DFJaEoi0.js.map +1 -0
- package/dist/client/assets/index-UheDso2P.js +2 -0
- package/dist/client/assets/index-UheDso2P.js.map +1 -0
- package/dist/client/assets/preview-CWdUATNl.js +4 -0
- package/dist/client/assets/preview-CWdUATNl.js.map +1 -0
- package/dist/client/assets/useQualityAnalysis-Cl4QPeOT.js +6 -0
- package/dist/client/assets/useQualityAnalysis-Cl4QPeOT.js.map +1 -0
- package/dist/client/index.html +2 -2
- package/dist/client/templates/client-report-blocks.docx.json +791 -0
- package/dist/client/templates/consulting-deck-blocks.pptx.json +455 -0
- package/dist/client/templates/data-report-presentation.pptx.json +108 -36
- package/dist/client/templates/management-plan.pptx.json +100 -22
- package/dist/client/templates/minimalist-pitch-deck.pptx.json +172 -101
- package/dist/prompts/instructions-edit-document-pptx-blocks.md +77 -0
- package/dist/prompts/instructions-edit-document-pptx-slides.md +15 -21
- package/dist/prompts/instructions-edit-document-pptx.md +34 -53
- package/dist/prompts/instructions-edit-pptx.md +9 -8
- package/dist/prompts/instructions-generate-pptx.md +13 -17
- package/dist/prompts/pptx-core.md +104 -127
- package/dist/prompts/pptx-design.md +115 -109
- package/package.json +10 -9
- package/dist/client/assets/HomePage-mtUb6jxc.js +0 -251
- package/dist/client/assets/HomePage-mtUb6jxc.js.map +0 -1
- package/dist/client/assets/_virtual_jto-sandbox-runtime-Dqq17bow.js +0 -2
- package/dist/client/assets/_virtual_jto-sandbox-runtime-Dqq17bow.js.map +0 -1
- package/dist/client/assets/editor-ZbEHVEFs.js +0 -16
- package/dist/client/assets/editor-ZbEHVEFs.js.map +0 -1
- package/dist/client/assets/editor-monaco-json-FaaVfftD.js +0 -24
- package/dist/client/assets/editor-monaco-json-FaaVfftD.js.map +0 -1
- package/dist/client/assets/editor-refs-store-DAEAPqEk.js +0 -2
- package/dist/client/assets/editor-refs-store-DAEAPqEk.js.map +0 -1
- package/dist/client/assets/index-Bj6ZAKUc.css +0 -1
- package/dist/client/assets/index-DRbATnbJ.js +0 -5
- package/dist/client/assets/index-DRbATnbJ.js.map +0 -1
- package/dist/client/assets/preview-CM2ywF-8.js +0 -4
- package/dist/client/assets/preview-CM2ywF-8.js.map +0 -1
- package/dist/client/assets/useQualityAnalysis-ClgkaIc2.js +0 -6
- package/dist/client/assets/useQualityAnalysis-ClgkaIc2.js.map +0 -1
- package/dist/prompts/instructions-edit-document-pptx-templates.md +0 -63
package/dist/cli.js
CHANGED
|
@@ -2914,14 +2914,79 @@ var init_browser_plugin_schema = __esm({
|
|
|
2914
2914
|
}
|
|
2915
2915
|
});
|
|
2916
2916
|
|
|
2917
|
+
// src/server/services/block-references.ts
|
|
2918
|
+
import { readFile } from "fs/promises";
|
|
2919
|
+
import { PluginDiscoveryService as PluginDiscoveryService2 } from "@json-to-office/jto-cli";
|
|
2920
|
+
import {
|
|
2921
|
+
blockReferencesFromDocument,
|
|
2922
|
+
blockSlotFacts
|
|
2923
|
+
} from "@json-to-office/shared";
|
|
2924
|
+
async function discoverBlockReferences(format) {
|
|
2925
|
+
const cached = cache.get(format);
|
|
2926
|
+
if (cached && Date.now() - cached.at < TTL_MS) return cached.references;
|
|
2927
|
+
const discovery = new PluginDiscoveryService2({
|
|
2928
|
+
maxDepth: 10,
|
|
2929
|
+
includeNodeModules: false,
|
|
2930
|
+
verbose: false
|
|
2931
|
+
});
|
|
2932
|
+
const documents = await discovery.discoverDocuments(format);
|
|
2933
|
+
const references = [];
|
|
2934
|
+
for (const document of documents) {
|
|
2935
|
+
try {
|
|
2936
|
+
references.push(
|
|
2937
|
+
...blockReferencesFromDocument(
|
|
2938
|
+
JSON.parse(await readFile(document.path, "utf-8")),
|
|
2939
|
+
{ template: document.name, format }
|
|
2940
|
+
)
|
|
2941
|
+
);
|
|
2942
|
+
} catch {
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
cache.set(format, { at: Date.now(), references });
|
|
2946
|
+
return references;
|
|
2947
|
+
}
|
|
2948
|
+
function blockReferencesPrompt(references) {
|
|
2949
|
+
if (!references.length)
|
|
2950
|
+
return "_No reference blocks are available on this server; define the blocks the deck needs yourself._";
|
|
2951
|
+
return references.map((reference) => {
|
|
2952
|
+
const slots = Object.entries(reference.definition.slots).map(
|
|
2953
|
+
([name, slot]) => `- \`${name}\` \u2014 ${[slot.type, ...blockSlotFacts(slot)].join(", ")}${slot.description ? `: ${slot.description}` : ""}`
|
|
2954
|
+
);
|
|
2955
|
+
const dependencies = reference.dependencies.length ? `
|
|
2956
|
+
Also copy: ${reference.dependencies.map((name) => `\`${name}\``).join(", ")} (invoked by this definition).` : "";
|
|
2957
|
+
return [
|
|
2958
|
+
`### \`${reference.name}\` (from ${reference.template})`,
|
|
2959
|
+
reference.description,
|
|
2960
|
+
slots.length ? slots.join("\n") : "_No slots._",
|
|
2961
|
+
`Definition to copy into \`props.blocks\`:${dependencies}`,
|
|
2962
|
+
"```json",
|
|
2963
|
+
JSON.stringify({ [reference.name]: reference.definition }, null, 2),
|
|
2964
|
+
"```",
|
|
2965
|
+
"Invocation:",
|
|
2966
|
+
"```json",
|
|
2967
|
+
JSON.stringify(reference.example, null, 2),
|
|
2968
|
+
"```"
|
|
2969
|
+
].filter(Boolean).join("\n\n");
|
|
2970
|
+
}).join("\n\n");
|
|
2971
|
+
}
|
|
2972
|
+
var TTL_MS, cache;
|
|
2973
|
+
var init_block_references = __esm({
|
|
2974
|
+
"src/server/services/block-references.ts"() {
|
|
2975
|
+
"use strict";
|
|
2976
|
+
init_esm_shims();
|
|
2977
|
+
TTL_MS = 1e4;
|
|
2978
|
+
cache = /* @__PURE__ */ new Map();
|
|
2979
|
+
}
|
|
2980
|
+
});
|
|
2981
|
+
|
|
2917
2982
|
// src/server/routes/discovery.ts
|
|
2918
2983
|
import { Hono as Hono3 } from "hono";
|
|
2919
2984
|
import { HTTPException as HTTPException5 } from "hono/http-exception";
|
|
2920
2985
|
import { bodyLimit as bodyLimit3 } from "hono/body-limit";
|
|
2921
2986
|
import { Type as Type3 } from "@sinclair/typebox";
|
|
2922
|
-
import { readFile, stat } from "fs/promises";
|
|
2987
|
+
import { readFile as readFile2, stat } from "fs/promises";
|
|
2923
2988
|
import {
|
|
2924
|
-
PluginDiscoveryService as
|
|
2989
|
+
PluginDiscoveryService as PluginDiscoveryService3,
|
|
2925
2990
|
PluginRegistry as PluginRegistry3
|
|
2926
2991
|
} from "@json-to-office/jto-cli";
|
|
2927
2992
|
import { latestVersion } from "@json-to-office/shared";
|
|
@@ -3085,6 +3150,7 @@ var init_discovery = __esm({
|
|
|
3085
3150
|
init_auth();
|
|
3086
3151
|
init_config();
|
|
3087
3152
|
init_browser_plugin_schema();
|
|
3153
|
+
init_block_references();
|
|
3088
3154
|
discoveryRouter = new Hono3();
|
|
3089
3155
|
BrowserPluginVersionSchema = Type3.Object(
|
|
3090
3156
|
{
|
|
@@ -3124,7 +3190,7 @@ var init_discovery = __esm({
|
|
|
3124
3190
|
discoveryRouter.get("/all", async (c) => {
|
|
3125
3191
|
try {
|
|
3126
3192
|
const format = Container.getAdapter().name;
|
|
3127
|
-
const discovery = new
|
|
3193
|
+
const discovery = new PluginDiscoveryService3({
|
|
3128
3194
|
maxDepth: 10,
|
|
3129
3195
|
includeNodeModules: false,
|
|
3130
3196
|
verbose: false
|
|
@@ -3159,7 +3225,7 @@ var init_discovery = __esm({
|
|
|
3159
3225
|
const includeSchemas = c.req.query("schemas") === "true";
|
|
3160
3226
|
const includeExamples = c.req.query("examples") === "true";
|
|
3161
3227
|
const format = Container.getAdapter().name;
|
|
3162
|
-
const discovery = new
|
|
3228
|
+
const discovery = new PluginDiscoveryService3({
|
|
3163
3229
|
maxDepth: 10,
|
|
3164
3230
|
includeNodeModules: false,
|
|
3165
3231
|
verbose: false
|
|
@@ -3191,7 +3257,7 @@ var init_discovery = __esm({
|
|
|
3191
3257
|
discoveryRouter.get("/documents", async (c) => {
|
|
3192
3258
|
try {
|
|
3193
3259
|
const format = Container.getAdapter().name;
|
|
3194
|
-
const discovery = new
|
|
3260
|
+
const discovery = new PluginDiscoveryService3({
|
|
3195
3261
|
maxDepth: 10,
|
|
3196
3262
|
includeNodeModules: false,
|
|
3197
3263
|
verbose: false
|
|
@@ -3203,10 +3269,24 @@ var init_discovery = __esm({
|
|
|
3203
3269
|
return c.json({ success: false, error: error.message }, 500);
|
|
3204
3270
|
}
|
|
3205
3271
|
});
|
|
3272
|
+
discoveryRouter.get("/blocks", async (c) => {
|
|
3273
|
+
try {
|
|
3274
|
+
const format = Container.getAdapter().name;
|
|
3275
|
+
const references = await discoverBlockReferences(format);
|
|
3276
|
+
return c.json({
|
|
3277
|
+
success: true,
|
|
3278
|
+
data: references,
|
|
3279
|
+
count: references.length
|
|
3280
|
+
});
|
|
3281
|
+
} catch (error) {
|
|
3282
|
+
logger.error("Block discovery failed", { error: error.message });
|
|
3283
|
+
return c.json({ success: false, error: error.message }, 500);
|
|
3284
|
+
}
|
|
3285
|
+
});
|
|
3206
3286
|
discoveryRouter.get("/themes", async (c) => {
|
|
3207
3287
|
try {
|
|
3208
3288
|
const format = Container.getAdapter().name;
|
|
3209
|
-
const discovery = new
|
|
3289
|
+
const discovery = new PluginDiscoveryService3({
|
|
3210
3290
|
maxDepth: 10,
|
|
3211
3291
|
includeNodeModules: false,
|
|
3212
3292
|
verbose: false
|
|
@@ -3241,7 +3321,7 @@ var init_discovery = __esm({
|
|
|
3241
3321
|
try {
|
|
3242
3322
|
const pluginName = c.req.param("name");
|
|
3243
3323
|
const format = Container.getAdapter().name;
|
|
3244
|
-
const discovery = new
|
|
3324
|
+
const discovery = new PluginDiscoveryService3({
|
|
3245
3325
|
maxDepth: 10,
|
|
3246
3326
|
includeNodeModules: false,
|
|
3247
3327
|
verbose: false
|
|
@@ -3261,7 +3341,7 @@ var init_discovery = __esm({
|
|
|
3261
3341
|
413
|
|
3262
3342
|
);
|
|
3263
3343
|
}
|
|
3264
|
-
return c.text(await
|
|
3344
|
+
return c.text(await readFile2(plugin.filePath, "utf-8"));
|
|
3265
3345
|
} catch (error) {
|
|
3266
3346
|
logger.error("Plugin source read failed", { error: error.message });
|
|
3267
3347
|
return c.json({ success: false, error: error.message }, 500);
|
|
@@ -3271,7 +3351,7 @@ var init_discovery = __esm({
|
|
|
3271
3351
|
try {
|
|
3272
3352
|
const pluginName = c.req.param("name");
|
|
3273
3353
|
const format = Container.getAdapter().name;
|
|
3274
|
-
const discovery = new
|
|
3354
|
+
const discovery = new PluginDiscoveryService3({
|
|
3275
3355
|
maxDepth: 10,
|
|
3276
3356
|
includeNodeModules: false,
|
|
3277
3357
|
verbose: false
|
|
@@ -3306,7 +3386,7 @@ var init_discovery = __esm({
|
|
|
3306
3386
|
try {
|
|
3307
3387
|
const name = c.req.param("name");
|
|
3308
3388
|
const format = Container.getAdapter().name;
|
|
3309
|
-
const discovery = new
|
|
3389
|
+
const discovery = new PluginDiscoveryService3({
|
|
3310
3390
|
maxDepth: 10,
|
|
3311
3391
|
includeNodeModules: false,
|
|
3312
3392
|
verbose: false
|
|
@@ -3322,7 +3402,7 @@ var init_discovery = __esm({
|
|
|
3322
3402
|
try {
|
|
3323
3403
|
const name = c.req.param("name");
|
|
3324
3404
|
const format = Container.getAdapter().name;
|
|
3325
|
-
const discovery = new
|
|
3405
|
+
const discovery = new PluginDiscoveryService3({
|
|
3326
3406
|
maxDepth: 10,
|
|
3327
3407
|
includeNodeModules: false,
|
|
3328
3408
|
verbose: false
|
|
@@ -3507,10 +3587,10 @@ function resolvePromptsDir() {
|
|
|
3507
3587
|
return candidates[0];
|
|
3508
3588
|
}
|
|
3509
3589
|
function readPromptFile(name) {
|
|
3510
|
-
if (
|
|
3590
|
+
if (cache2.has(name)) return cache2.get(name);
|
|
3511
3591
|
const filePath = join(PROMPTS_DIR, name);
|
|
3512
3592
|
const content = readFileSync(filePath, "utf-8");
|
|
3513
|
-
|
|
3593
|
+
cache2.set(name, content);
|
|
3514
3594
|
return content;
|
|
3515
3595
|
}
|
|
3516
3596
|
function loadPrompt(name, vars = {}) {
|
|
@@ -3520,14 +3600,14 @@ function loadPrompt(name, vars = {}) {
|
|
|
3520
3600
|
}
|
|
3521
3601
|
return content;
|
|
3522
3602
|
}
|
|
3523
|
-
var __dirname2, PROMPTS_DIR,
|
|
3603
|
+
var __dirname2, PROMPTS_DIR, cache2;
|
|
3524
3604
|
var init_prompt_loader = __esm({
|
|
3525
3605
|
"src/server/services/prompt-loader.ts"() {
|
|
3526
3606
|
"use strict";
|
|
3527
3607
|
init_esm_shims();
|
|
3528
3608
|
__dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
3529
3609
|
PROMPTS_DIR = resolvePromptsDir();
|
|
3530
|
-
|
|
3610
|
+
cache2 = /* @__PURE__ */ new Map();
|
|
3531
3611
|
}
|
|
3532
3612
|
});
|
|
3533
3613
|
|
|
@@ -3536,6 +3616,7 @@ import { Hono as Hono4 } from "hono";
|
|
|
3536
3616
|
import { streamText, convertToModelMessages } from "ai";
|
|
3537
3617
|
import { claudeCode } from "ai-sdk-provider-claude-code";
|
|
3538
3618
|
import { extractText as extractPdfText } from "unpdf";
|
|
3619
|
+
import { blockSlotFacts as blockSlotFacts2 } from "@json-to-office/shared";
|
|
3539
3620
|
function sanitizeFilename(name) {
|
|
3540
3621
|
return name.replace(/[[\]\n\r]/g, "_");
|
|
3541
3622
|
}
|
|
@@ -3688,7 +3769,11 @@ function createAiRouter() {
|
|
|
3688
3769
|
const hasActiveDoc = !hasSelection && activeDocument?.text;
|
|
3689
3770
|
const isGenerate = !hasSelection && !hasActiveDoc;
|
|
3690
3771
|
if (!isTheme && format === "pptx" && !hasSelection) {
|
|
3691
|
-
systemPrompt += "\n\n" + loadPrompt("pptx-design.md"
|
|
3772
|
+
systemPrompt += "\n\n" + loadPrompt("pptx-design.md", {
|
|
3773
|
+
referenceBlocks: blockReferencesPrompt(
|
|
3774
|
+
await discoverBlockReferences("pptx")
|
|
3775
|
+
)
|
|
3776
|
+
});
|
|
3692
3777
|
}
|
|
3693
3778
|
if (hasSelection) {
|
|
3694
3779
|
const ctx = context[0];
|
|
@@ -3699,7 +3784,7 @@ function createAiRouter() {
|
|
|
3699
3784
|
selectedText: ctx.selectedText
|
|
3700
3785
|
});
|
|
3701
3786
|
} else if (hasActiveDoc) {
|
|
3702
|
-
const pptxScope = format === "pptx" && !isTheme && (scope === "slides" || scope === "
|
|
3787
|
+
const pptxScope = format === "pptx" && !isTheme && (scope === "slides" || scope === "blocks");
|
|
3703
3788
|
let parsedDoc = null;
|
|
3704
3789
|
if (pptxScope) {
|
|
3705
3790
|
try {
|
|
@@ -3709,38 +3794,36 @@ function createAiRouter() {
|
|
|
3709
3794
|
}
|
|
3710
3795
|
if (pptxScope && parsedDoc) {
|
|
3711
3796
|
const doc = parsedDoc;
|
|
3797
|
+
const blocks = doc.props?.blocks || {};
|
|
3798
|
+
const invoked = (slide) => (slide.children || []).filter((child) => child?.name === "block").map((child) => String(child.props?.ref ?? "?"));
|
|
3712
3799
|
if (scope === "slides") {
|
|
3713
|
-
const
|
|
3714
|
-
const
|
|
3715
|
-
const
|
|
3716
|
-
|
|
3800
|
+
const blocksSummary = Object.entries(blocks).map(([name, definition]) => {
|
|
3801
|
+
const slots = Object.entries(definition.slots || {}).map(([slot, spec]) => {
|
|
3802
|
+
const facts = [spec.type, ...blockSlotFacts2(spec)];
|
|
3803
|
+
const description2 = spec.description ? `: ${spec.description}` : "";
|
|
3804
|
+
return ` - \`${slot}\` \u2014 ${facts.join(", ")}${description2}`;
|
|
3717
3805
|
}).join("\n");
|
|
3718
|
-
|
|
3719
|
-
|
|
3806
|
+
const description = definition.description ? ` \u2014 ${definition.description}` : "";
|
|
3807
|
+
return `**${name}**${description}
|
|
3808
|
+
${slots || " _No slots._"}`;
|
|
3720
3809
|
}).join("\n\n");
|
|
3721
3810
|
const slidesText = JSON.stringify(doc.children || [], null, 2);
|
|
3722
3811
|
systemPrompt += "\n\n" + loadPrompt("instructions-edit-document-pptx-slides.md", {
|
|
3723
3812
|
documentName: activeDocument.name || "untitled",
|
|
3724
|
-
|
|
3813
|
+
blocksSummary: blocksSummary || "_No blocks defined yet._",
|
|
3725
3814
|
slidesText
|
|
3726
3815
|
});
|
|
3727
3816
|
} else {
|
|
3728
|
-
const
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
const slidesSummary = (doc.children || []).map((s, i) => {
|
|
3734
|
-
const template = s.props?.template || "(none)";
|
|
3735
|
-
const phs = Object.keys(s.props?.placeholders || {}).join(
|
|
3736
|
-
", "
|
|
3737
|
-
);
|
|
3738
|
-
return ` ${i}: template=${template}, placeholders=[${phs}]`;
|
|
3817
|
+
const blocksText = JSON.stringify(blocks, null, 2);
|
|
3818
|
+
const slidesSummary = (doc.children || []).map((slide, index) => {
|
|
3819
|
+
const title = slide.props?.meta?.title ? ` "${slide.props.meta.title}"` : "";
|
|
3820
|
+
const refs = invoked(slide);
|
|
3821
|
+
return ` ${index}:${title} blocks=[${refs.join(", ")}]`;
|
|
3739
3822
|
}).join("\n");
|
|
3740
|
-
systemPrompt += "\n\n" + loadPrompt("instructions-edit-document-pptx-
|
|
3823
|
+
systemPrompt += "\n\n" + loadPrompt("instructions-edit-document-pptx-blocks.md", {
|
|
3741
3824
|
documentName: activeDocument.name || "untitled",
|
|
3742
|
-
|
|
3743
|
-
slidesSummary
|
|
3825
|
+
blocksText,
|
|
3826
|
+
slidesSummary: slidesSummary || " _No slides yet._"
|
|
3744
3827
|
});
|
|
3745
3828
|
}
|
|
3746
3829
|
} else {
|
|
@@ -3860,6 +3943,7 @@ var init_ai = __esm({
|
|
|
3860
3943
|
init_esm_shims();
|
|
3861
3944
|
init_ai_schema();
|
|
3862
3945
|
init_prompt_loader();
|
|
3946
|
+
init_block_references();
|
|
3863
3947
|
init_logger();
|
|
3864
3948
|
init_rate_limit();
|
|
3865
3949
|
init_config();
|
|
@@ -4735,7 +4819,7 @@ function createDevCommand(adapter) {
|
|
|
4735
4819
|
}
|
|
4736
4820
|
|
|
4737
4821
|
// src/cli.ts
|
|
4738
|
-
var PACKAGE_VERSION = true ? "
|
|
4822
|
+
var PACKAGE_VERSION = true ? "3.0.0" : "dev-mode";
|
|
4739
4823
|
var program = new Command2();
|
|
4740
4824
|
program.name("jto").description("JSON to Office CLI - Generate .docx and .pptx from JSON").version(PACKAGE_VERSION);
|
|
4741
4825
|
registerCoreCommands(program, {
|