@mtreeai/msapling-cli 2.3.6-beta.13 → 2.3.6-beta.14
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/index.js +63 -81
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3620,20 +3620,20 @@ async function copyDir(src, dst) {
|
|
|
3620
3620
|
}
|
|
3621
3621
|
async function backupFile(absPath) {
|
|
3622
3622
|
try {
|
|
3623
|
-
const { readFile:
|
|
3623
|
+
const { readFile: readFile22, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
|
|
3624
3624
|
const { homedir: homedir17 } = await import("os");
|
|
3625
|
-
const { join:
|
|
3625
|
+
const { join: join30 } = await import("path");
|
|
3626
3626
|
const filename = absPath.split(/[\\/]/).pop() ?? "file";
|
|
3627
3627
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3628
3628
|
const suffix = randomBytes5(4).toString("hex");
|
|
3629
|
-
const backupPath =
|
|
3629
|
+
const backupPath = join30(
|
|
3630
3630
|
homedir17(),
|
|
3631
3631
|
".msapling",
|
|
3632
3632
|
"backups",
|
|
3633
3633
|
`${filename}.backup-${stamp}-${suffix}.bak`
|
|
3634
3634
|
);
|
|
3635
|
-
await mkdir9(
|
|
3636
|
-
const content = await
|
|
3635
|
+
await mkdir9(join30(homedir17(), ".msapling", "backups"), { recursive: true });
|
|
3636
|
+
const content = await readFile22(absPath, "utf8");
|
|
3637
3637
|
await writeFile12(backupPath, content, "utf8");
|
|
3638
3638
|
return backupPath;
|
|
3639
3639
|
} catch {
|
|
@@ -3859,9 +3859,9 @@ var init_DeleteFileTool = __esm({
|
|
|
3859
3859
|
let backedUpTo = null;
|
|
3860
3860
|
if (isFile) {
|
|
3861
3861
|
try {
|
|
3862
|
-
const { readFile:
|
|
3862
|
+
const { readFile: readFile22, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
|
|
3863
3863
|
const { homedir: homedir17 } = await import("os");
|
|
3864
|
-
const existingContent = await
|
|
3864
|
+
const existingContent = await readFile22(abs, "utf8");
|
|
3865
3865
|
const filename = abs.split(/[\\/]/).pop() ?? "file";
|
|
3866
3866
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3867
3867
|
const suffix = randomBytes6(4).toString("hex");
|
|
@@ -5834,8 +5834,8 @@ var require_graceful_fs = __commonJS({
|
|
|
5834
5834
|
fs4.createReadStream = createReadStream;
|
|
5835
5835
|
fs4.createWriteStream = createWriteStream;
|
|
5836
5836
|
var fs$readFile = fs4.readFile;
|
|
5837
|
-
fs4.readFile =
|
|
5838
|
-
function
|
|
5837
|
+
fs4.readFile = readFile22;
|
|
5838
|
+
function readFile22(path2, options, cb) {
|
|
5839
5839
|
if (typeof options === "function")
|
|
5840
5840
|
cb = options, options = null;
|
|
5841
5841
|
return go$readFile(path2, options, cb);
|
|
@@ -9669,22 +9669,9 @@ Available themes: ${VALID_THEMES.join(", ")}`);
|
|
|
9669
9669
|
});
|
|
9670
9670
|
|
|
9671
9671
|
// src/commands/version.ts
|
|
9672
|
-
import { join as join23 } from "path";
|
|
9673
|
-
import { existsSync as existsSync21 } from "fs";
|
|
9674
|
-
import { readFile as readFile19 } from "fs/promises";
|
|
9675
9672
|
function row2(label, value) {
|
|
9676
9673
|
return `${label.padEnd(COL_LABEL2)} ${value}`;
|
|
9677
9674
|
}
|
|
9678
|
-
async function readPackageVersion(pkgPath) {
|
|
9679
|
-
try {
|
|
9680
|
-
if (!existsSync21(pkgPath)) return "(not found)";
|
|
9681
|
-
const text = await readFile19(pkgPath, "utf8");
|
|
9682
|
-
const json = JSON.parse(text);
|
|
9683
|
-
return json.version ?? "(unknown)";
|
|
9684
|
-
} catch {
|
|
9685
|
-
return "(error reading)";
|
|
9686
|
-
}
|
|
9687
|
-
}
|
|
9688
9675
|
var COL_LABEL2, versionCommand;
|
|
9689
9676
|
var init_version = __esm({
|
|
9690
9677
|
"src/commands/version.ts"() {
|
|
@@ -9697,21 +9684,16 @@ var init_version = __esm({
|
|
|
9697
9684
|
description: "Show version information for CLI and core packages",
|
|
9698
9685
|
category: "debug",
|
|
9699
9686
|
handler: async (_args, context) => {
|
|
9700
|
-
const
|
|
9701
|
-
const
|
|
9702
|
-
const corePkgPath = join23(baseDir, "..", "..", "..", "core", "package.json");
|
|
9703
|
-
const [cliVersion, coreVersion] = await Promise.all([
|
|
9704
|
-
readPackageVersion(cliPkgPath),
|
|
9705
|
-
readPackageVersion(corePkgPath)
|
|
9706
|
-
]);
|
|
9687
|
+
const cliVersion = true ? "2.3.6-beta.14" : "(dev)";
|
|
9688
|
+
const coreVersion = true ? "2.3.2" : "(dev)";
|
|
9707
9689
|
const runtime = process.version;
|
|
9708
9690
|
context.addMessage("system", "MSapling Version Info");
|
|
9709
9691
|
context.addMessage("system", "\u2500".repeat(40));
|
|
9710
|
-
context.addMessage("system", row2("CLI (@msapling
|
|
9692
|
+
context.addMessage("system", row2("CLI (@mtreeai/msapling-cli)", cliVersion));
|
|
9711
9693
|
context.addMessage("system", row2("Core (@msapling/core)", coreVersion));
|
|
9712
9694
|
context.addMessage("system", row2("Runtime (Node/Bun)", runtime));
|
|
9713
9695
|
try {
|
|
9714
|
-
const ts =
|
|
9696
|
+
const ts = "2026-05-28T13:59:33.347Z";
|
|
9715
9697
|
if (ts && ts !== "__BUILD_TIMESTAMP__") {
|
|
9716
9698
|
context.addMessage("system", row2("Build Timestamp", ts));
|
|
9717
9699
|
}
|
|
@@ -9724,15 +9706,15 @@ var init_version = __esm({
|
|
|
9724
9706
|
});
|
|
9725
9707
|
|
|
9726
9708
|
// src/commands/feedback.ts
|
|
9727
|
-
import { join as
|
|
9728
|
-
import { existsSync as
|
|
9729
|
-
import { readFile as
|
|
9709
|
+
import { join as join23 } from "path";
|
|
9710
|
+
import { existsSync as existsSync21 } from "fs";
|
|
9711
|
+
import { readFile as readFile19 } from "fs/promises";
|
|
9730
9712
|
async function readCliVersion() {
|
|
9731
9713
|
try {
|
|
9732
9714
|
const baseDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
9733
|
-
const pkgPath =
|
|
9734
|
-
if (!
|
|
9735
|
-
const text = await
|
|
9715
|
+
const pkgPath = join23(baseDir, "..", "..", "package.json");
|
|
9716
|
+
if (!existsSync21(pkgPath)) return "unknown";
|
|
9717
|
+
const text = await readFile19(pkgPath, "utf8");
|
|
9736
9718
|
const json = JSON.parse(text);
|
|
9737
9719
|
return json.version ?? "unknown";
|
|
9738
9720
|
} catch {
|
|
@@ -9773,7 +9755,7 @@ var init_feedback = __esm({
|
|
|
9773
9755
|
|
|
9774
9756
|
// src/commands/export.ts
|
|
9775
9757
|
import { homedir as homedir13 } from "os";
|
|
9776
|
-
import { join as
|
|
9758
|
+
import { join as join24 } from "path";
|
|
9777
9759
|
import { writeFile as writeFile10, mkdir as mkdir8 } from "fs/promises";
|
|
9778
9760
|
function formatTimestamp(date) {
|
|
9779
9761
|
return date.toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
|
|
@@ -9823,10 +9805,10 @@ var init_export = __esm({
|
|
|
9823
9805
|
let outputPath;
|
|
9824
9806
|
let content;
|
|
9825
9807
|
if (arg === "" || arg === "json") {
|
|
9826
|
-
outputPath =
|
|
9808
|
+
outputPath = join24(homedir13(), `msapling-export-${timestamp}.json`);
|
|
9827
9809
|
content = buildJsonExport(history);
|
|
9828
9810
|
} else if (arg === "markdown" || arg === "md") {
|
|
9829
|
-
outputPath =
|
|
9811
|
+
outputPath = join24(homedir13(), `msapling-export-${timestamp}.md`);
|
|
9830
9812
|
content = buildMarkdownExport(history);
|
|
9831
9813
|
} else {
|
|
9832
9814
|
outputPath = arg;
|
|
@@ -9838,7 +9820,7 @@ var init_export = __esm({
|
|
|
9838
9820
|
}
|
|
9839
9821
|
}
|
|
9840
9822
|
try {
|
|
9841
|
-
const dir =
|
|
9823
|
+
const dir = join24(outputPath, "..");
|
|
9842
9824
|
await mkdir8(dir, { recursive: true });
|
|
9843
9825
|
await writeFile10(outputPath, content, "utf8");
|
|
9844
9826
|
context.addMessage("system", `Exported to: ${outputPath}`);
|
|
@@ -10034,16 +10016,16 @@ var init_plan = __esm({
|
|
|
10034
10016
|
|
|
10035
10017
|
// src/commands/note.ts
|
|
10036
10018
|
import { homedir as homedir14 } from "os";
|
|
10037
|
-
import { join as
|
|
10038
|
-
import { existsSync as
|
|
10039
|
-
import { readFile as
|
|
10019
|
+
import { join as join25 } from "path";
|
|
10020
|
+
import { existsSync as existsSync22 } from "fs";
|
|
10021
|
+
import { readFile as readFile20, writeFile as writeFile11 } from "fs/promises";
|
|
10040
10022
|
function getNotesFilePath() {
|
|
10041
|
-
return
|
|
10023
|
+
return join25(homedir14(), ".msapling", "notes.json");
|
|
10042
10024
|
}
|
|
10043
10025
|
async function readNotes(filePath = getNotesFilePath()) {
|
|
10044
10026
|
try {
|
|
10045
|
-
if (!
|
|
10046
|
-
const raw = await
|
|
10027
|
+
if (!existsSync22(filePath)) return [];
|
|
10028
|
+
const raw = await readFile20(filePath, "utf8");
|
|
10047
10029
|
const parsed = JSON.parse(raw);
|
|
10048
10030
|
if (!Array.isArray(parsed)) return [];
|
|
10049
10031
|
return parsed;
|
|
@@ -10052,7 +10034,7 @@ async function readNotes(filePath = getNotesFilePath()) {
|
|
|
10052
10034
|
}
|
|
10053
10035
|
}
|
|
10054
10036
|
async function writeNotes(notes, filePath = getNotesFilePath()) {
|
|
10055
|
-
const dir =
|
|
10037
|
+
const dir = join25(homedir14(), ".msapling");
|
|
10056
10038
|
ensureConfigDir(dir);
|
|
10057
10039
|
await writeFile11(filePath, JSON.stringify(notes, null, 2), "utf8");
|
|
10058
10040
|
}
|
|
@@ -10199,13 +10181,13 @@ var init_todo = __esm({
|
|
|
10199
10181
|
|
|
10200
10182
|
// src/commands/outputStyle.ts
|
|
10201
10183
|
import { homedir as homedir15 } from "os";
|
|
10202
|
-
import { join as
|
|
10203
|
-
import { existsSync as
|
|
10184
|
+
import { join as join26, basename, extname as extname3 } from "path";
|
|
10185
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
10204
10186
|
function stylesDir() {
|
|
10205
|
-
return
|
|
10187
|
+
return join26(homedir15(), ".msapling", "output-styles");
|
|
10206
10188
|
}
|
|
10207
10189
|
function activeFile() {
|
|
10208
|
-
return
|
|
10190
|
+
return join26(stylesDir(), ".active");
|
|
10209
10191
|
}
|
|
10210
10192
|
function parseStyleFile(text) {
|
|
10211
10193
|
const fm = text.match(/^---\s*\n([\s\S]*?)\n---\s*\n?/);
|
|
@@ -10226,11 +10208,11 @@ function parseStyleFile(text) {
|
|
|
10226
10208
|
}
|
|
10227
10209
|
function listUserStyles() {
|
|
10228
10210
|
const dir = stylesDir();
|
|
10229
|
-
if (!
|
|
10211
|
+
if (!existsSync23(dir)) return [];
|
|
10230
10212
|
const out = [];
|
|
10231
10213
|
for (const entry of readdirSync3(dir)) {
|
|
10232
10214
|
if (extname3(entry).toLowerCase() !== ".md") continue;
|
|
10233
|
-
const full =
|
|
10215
|
+
const full = join26(dir, entry);
|
|
10234
10216
|
try {
|
|
10235
10217
|
const text = readFileSync(full, "utf8");
|
|
10236
10218
|
const { description, body } = parseStyleFile(text);
|
|
@@ -10258,7 +10240,7 @@ function findStyle(name) {
|
|
|
10258
10240
|
function getActiveStyleName() {
|
|
10259
10241
|
try {
|
|
10260
10242
|
const f = activeFile();
|
|
10261
|
-
if (!
|
|
10243
|
+
if (!existsSync23(f)) return "default";
|
|
10262
10244
|
return readFileSync(f, "utf8").trim() || "default";
|
|
10263
10245
|
} catch {
|
|
10264
10246
|
return "default";
|
|
@@ -10266,7 +10248,7 @@ function getActiveStyleName() {
|
|
|
10266
10248
|
}
|
|
10267
10249
|
function setActiveStyleName(name) {
|
|
10268
10250
|
const dir = stylesDir();
|
|
10269
|
-
if (!
|
|
10251
|
+
if (!existsSync23(dir)) mkdirSync5(dir, { recursive: true });
|
|
10270
10252
|
writeFileSync2(activeFile(), `${name}
|
|
10271
10253
|
`, "utf8");
|
|
10272
10254
|
}
|
|
@@ -10279,8 +10261,8 @@ function createUserStyle(name, description, body) {
|
|
|
10279
10261
|
throw new Error(`Invalid style name "${name}" \u2014 use letters, digits, _ and - only.`);
|
|
10280
10262
|
}
|
|
10281
10263
|
const dir = stylesDir();
|
|
10282
|
-
if (!
|
|
10283
|
-
const target =
|
|
10264
|
+
if (!existsSync23(dir)) mkdirSync5(dir, { recursive: true });
|
|
10265
|
+
const target = join26(dir, `${name}.md`);
|
|
10284
10266
|
const frontmatter = `---
|
|
10285
10267
|
description: ${description.replace(/\n/g, " ")}
|
|
10286
10268
|
---
|
|
@@ -10647,8 +10629,8 @@ __export(doctor_exports, {
|
|
|
10647
10629
|
runDoctor: () => runDoctor
|
|
10648
10630
|
});
|
|
10649
10631
|
import { homedir as homedir16, platform as platform3 } from "os";
|
|
10650
|
-
import { join as
|
|
10651
|
-
import { existsSync as
|
|
10632
|
+
import { join as join27 } from "path";
|
|
10633
|
+
import { existsSync as existsSync25, statSync as statSync6, accessSync } from "fs";
|
|
10652
10634
|
import { readdir as readdir3 } from "fs/promises";
|
|
10653
10635
|
import { exec } from "child_process";
|
|
10654
10636
|
import { promisify } from "util";
|
|
@@ -10671,8 +10653,8 @@ async function checkNodeVersion() {
|
|
|
10671
10653
|
};
|
|
10672
10654
|
}
|
|
10673
10655
|
async function checkConfigDir() {
|
|
10674
|
-
const configDir =
|
|
10675
|
-
if (!
|
|
10656
|
+
const configDir = join27(homedir16(), ".msapling");
|
|
10657
|
+
if (!existsSync25(configDir)) {
|
|
10676
10658
|
return {
|
|
10677
10659
|
name: "Config directory",
|
|
10678
10660
|
status: "WARN",
|
|
@@ -10738,12 +10720,12 @@ async function checkPathConflicts() {
|
|
|
10738
10720
|
const paths = pathEnv.split(platform3() === "win32" ? ";" : ":");
|
|
10739
10721
|
const conflicts = [];
|
|
10740
10722
|
for (const dir of paths) {
|
|
10741
|
-
if (!dir || !
|
|
10723
|
+
if (!dir || !existsSync25(dir)) continue;
|
|
10742
10724
|
try {
|
|
10743
10725
|
const files = await readdir3(dir);
|
|
10744
10726
|
for (const file of files) {
|
|
10745
10727
|
if (file === "msapling" || file === "msapling.exe" || file === "msapling.py") {
|
|
10746
|
-
const fullPath =
|
|
10728
|
+
const fullPath = join27(dir, file);
|
|
10747
10729
|
conflicts.push(fullPath);
|
|
10748
10730
|
}
|
|
10749
10731
|
}
|
|
@@ -10845,9 +10827,9 @@ async function checkTokenValidity() {
|
|
|
10845
10827
|
async function checkOsSpecific() {
|
|
10846
10828
|
if (platform3() === "win32") {
|
|
10847
10829
|
try {
|
|
10848
|
-
const configDir =
|
|
10830
|
+
const configDir = join27(homedir16(), ".msapling");
|
|
10849
10831
|
const longPath = "A".repeat(260);
|
|
10850
|
-
const testPath =
|
|
10832
|
+
const testPath = join27(configDir, longPath);
|
|
10851
10833
|
try {
|
|
10852
10834
|
accessSync(configDir);
|
|
10853
10835
|
} catch {
|
|
@@ -12509,7 +12491,7 @@ __export(server_exports, {
|
|
|
12509
12491
|
runStdioWithRegistry: () => runStdioWithRegistry
|
|
12510
12492
|
});
|
|
12511
12493
|
import { readdirSync as readdirSync4, readFileSync as readFileSync2, statSync as statSync7 } from "fs";
|
|
12512
|
-
import { join as
|
|
12494
|
+
import { join as join28, relative as relative14, resolve as resolve17 } from "path";
|
|
12513
12495
|
function asResult2(text, isError = false) {
|
|
12514
12496
|
return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
|
|
12515
12497
|
}
|
|
@@ -12529,7 +12511,7 @@ function buildFileTree(root, maxFiles) {
|
|
|
12529
12511
|
for (const name of entries) {
|
|
12530
12512
|
if (out.length >= maxFiles) break;
|
|
12531
12513
|
if (SKIP_DIRS2.has(name)) continue;
|
|
12532
|
-
const full =
|
|
12514
|
+
const full = join28(dir, name);
|
|
12533
12515
|
let s;
|
|
12534
12516
|
try {
|
|
12535
12517
|
s = statSync7(full);
|
|
@@ -13295,7 +13277,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
13295
13277
|
var Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
|
|
13296
13278
|
/* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
13297
13279
|
"\u25CF MSapling CLI v",
|
|
13298
|
-
"2.3.6-beta.
|
|
13280
|
+
"2.3.6-beta.14"
|
|
13299
13281
|
] }),
|
|
13300
13282
|
/* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
|
|
13301
13283
|
] });
|
|
@@ -13818,10 +13800,10 @@ ${prompt}` : prompt;
|
|
|
13818
13800
|
for (const mention of fileMentions) {
|
|
13819
13801
|
const filePath = mention.slice(1);
|
|
13820
13802
|
try {
|
|
13821
|
-
const { existsSync:
|
|
13822
|
-
const { readFile:
|
|
13823
|
-
if (
|
|
13824
|
-
const content = await
|
|
13803
|
+
const { existsSync: existsSync26 } = await import("fs");
|
|
13804
|
+
const { readFile: readFile22 } = await import("fs/promises");
|
|
13805
|
+
if (existsSync26(filePath)) {
|
|
13806
|
+
const content = await readFile22(filePath, "utf8");
|
|
13825
13807
|
const MAX_LEN = 32768;
|
|
13826
13808
|
const truncated = content.length > MAX_LEN ? content.slice(0, MAX_LEN) + "\n...[TRUNCATED]" : content;
|
|
13827
13809
|
finalCmd += `
|
|
@@ -13872,8 +13854,8 @@ ${finalCmd}`;
|
|
|
13872
13854
|
// src/state/initSession.ts
|
|
13873
13855
|
init_esm_shims();
|
|
13874
13856
|
init_src3();
|
|
13875
|
-
import { readFile as
|
|
13876
|
-
import { existsSync as
|
|
13857
|
+
import { readFile as readFile21 } from "fs/promises";
|
|
13858
|
+
import { existsSync as existsSync24 } from "fs";
|
|
13877
13859
|
|
|
13878
13860
|
// src/state/parseApprovalMode.ts
|
|
13879
13861
|
init_esm_shims();
|
|
@@ -13947,10 +13929,10 @@ async function initSession(ctx) {
|
|
|
13947
13929
|
}
|
|
13948
13930
|
try {
|
|
13949
13931
|
const { homedir: homedir17 } = await import("os");
|
|
13950
|
-
const { join:
|
|
13951
|
-
const userSettingsPath =
|
|
13952
|
-
if (
|
|
13953
|
-
const userText = await
|
|
13932
|
+
const { join: join30 } = await import("path");
|
|
13933
|
+
const userSettingsPath = join30(homedir17(), ".msapling", "settings.json");
|
|
13934
|
+
if (existsSync24(userSettingsPath)) {
|
|
13935
|
+
const userText = await readFile21(userSettingsPath, "utf8");
|
|
13954
13936
|
let parsed;
|
|
13955
13937
|
try {
|
|
13956
13938
|
parsed = JSON.parse(userText);
|
|
@@ -14247,12 +14229,12 @@ var App = ({ compact: compact2 = false }) => {
|
|
|
14247
14229
|
init_esm_shims();
|
|
14248
14230
|
import { readFileSync as readFileSync3 } from "fs";
|
|
14249
14231
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
14250
|
-
import { dirname as dirname3, join as
|
|
14232
|
+
import { dirname as dirname3, join as join29 } from "path";
|
|
14251
14233
|
function readCliVersion2() {
|
|
14252
14234
|
const here = dirname3(fileURLToPath2(import.meta.url));
|
|
14253
14235
|
for (const rel of ["../package.json", "../../package.json"]) {
|
|
14254
14236
|
try {
|
|
14255
|
-
const pkg = JSON.parse(readFileSync3(
|
|
14237
|
+
const pkg = JSON.parse(readFileSync3(join29(here, rel), "utf8"));
|
|
14256
14238
|
if (pkg.name && pkg.version) {
|
|
14257
14239
|
return { name: pkg.name, version: pkg.version };
|
|
14258
14240
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mtreeai/msapling-cli",
|
|
3
|
-
"version": "2.3.6-beta.
|
|
3
|
+
"version": "2.3.6-beta.14",
|
|
4
4
|
"description": "MSapling CLI — React/Ink terminal client for the MSapling backend (chat, projects, MDrive, agent tools). Proprietary; redistribution prohibited.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "MSapling Team",
|