@supanadit/morse-web 0.11.0 → 0.12.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/server.mjs +149 -22
- package/dist/server.mjs.map +4 -4
- package/dist/ui/3rdpartylicenses.txt +34 -34
- package/dist/ui/{chunk-DA4X1qo9.js → chunk-BJlUk5wu.js} +1 -1
- package/dist/ui/{chunk-DD8oHaM3.js → chunk-C_meY2xd.js} +2 -2
- package/dist/ui/{chunk-C9z992Mq.js → chunk-DxDqTq2a.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/dist/ui/main-33GJA27U.js +120 -0
- package/dist/ui/webview.manifest.json +2 -2
- package/package.json +1 -1
- package/dist/ui/main-5C6SRPAD.js +0 -120
package/dist/server.mjs
CHANGED
|
@@ -1710,11 +1710,11 @@ function promptDescription(raw) {
|
|
|
1710
1710
|
}
|
|
1711
1711
|
body = raw.slice(frontmatter[0].length);
|
|
1712
1712
|
}
|
|
1713
|
-
const
|
|
1714
|
-
if (
|
|
1713
|
+
const firstLine = body.split("\n").find((line) => line.trim().length > 0);
|
|
1714
|
+
if (firstLine === void 0) {
|
|
1715
1715
|
return void 0;
|
|
1716
1716
|
}
|
|
1717
|
-
const trimmed =
|
|
1717
|
+
const trimmed = firstLine.trim();
|
|
1718
1718
|
return trimmed.length > 60 ? `${trimmed.slice(0, 60)}...` : trimmed;
|
|
1719
1719
|
}
|
|
1720
1720
|
function unquote(value) {
|
|
@@ -4253,7 +4253,10 @@ async function commitGit(cwd, message) {
|
|
|
4253
4253
|
return { ok: false, message: "This project is not a git repository." };
|
|
4254
4254
|
}
|
|
4255
4255
|
const result = await gitExec(["commit", "-m", text], cwd, 6e4);
|
|
4256
|
-
|
|
4256
|
+
if (result.ok) {
|
|
4257
|
+
return { ok: true };
|
|
4258
|
+
}
|
|
4259
|
+
return { ok: false, message: describeCommitFailure(result.output) };
|
|
4257
4260
|
}
|
|
4258
4261
|
async function checkoutGit(cwd, branch, create) {
|
|
4259
4262
|
const name = branch.trim();
|
|
@@ -4269,13 +4272,21 @@ async function checkoutGit(cwd, branch, create) {
|
|
|
4269
4272
|
cwd,
|
|
4270
4273
|
6e4
|
|
4271
4274
|
);
|
|
4272
|
-
return { ok: result.ok, message: result.ok ? void 0 :
|
|
4275
|
+
return { ok: result.ok, message: result.ok ? void 0 : gitRefusal(result.output) };
|
|
4273
4276
|
}
|
|
4274
4277
|
function isBranchName(name) {
|
|
4275
4278
|
return name.length > 0 && !name.startsWith("-") && !name.includes("..") && !name.includes("@{") && !name.endsWith("/") && !/\s/.test(name) && !/[~^:?*\[\\]/.test(name);
|
|
4276
4279
|
}
|
|
4277
|
-
function
|
|
4278
|
-
|
|
4280
|
+
function describeCommitFailure(output) {
|
|
4281
|
+
if (/nothing to commit|no changes added to commit|nothing added to commit/i.test(output)) {
|
|
4282
|
+
return "Nothing is staged to commit. Stage a change first.";
|
|
4283
|
+
}
|
|
4284
|
+
return gitRefusal(output);
|
|
4285
|
+
}
|
|
4286
|
+
function gitRefusal(output) {
|
|
4287
|
+
const line = output.split("\n").map((candidate) => candidate.trim()).find(
|
|
4288
|
+
(candidate) => candidate.length > 0 && !candidate.startsWith("Command failed:") && !/^On branch /.test(candidate) && !/^Your branch /.test(candidate)
|
|
4289
|
+
);
|
|
4279
4290
|
if (line === void 0) {
|
|
4280
4291
|
return void 0;
|
|
4281
4292
|
}
|
|
@@ -4359,9 +4370,12 @@ function gitExec(args, cwd, timeout = 5e3) {
|
|
|
4359
4370
|
}
|
|
4360
4371
|
},
|
|
4361
4372
|
(error, stdout, stderr) => {
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4373
|
+
if (error === null) {
|
|
4374
|
+
resolve6({ ok: true, output: stdout.trim() });
|
|
4375
|
+
return;
|
|
4376
|
+
}
|
|
4377
|
+
const output = [stderr.trim(), stdout.trim()].filter((part) => part.length > 0).join("\n");
|
|
4378
|
+
resolve6({ ok: false, output: output.length > 0 ? output : error.message.trim() });
|
|
4365
4379
|
}
|
|
4366
4380
|
);
|
|
4367
4381
|
});
|
|
@@ -4498,6 +4512,81 @@ function toPosix3(path) {
|
|
|
4498
4512
|
return path.split("\\").join("/");
|
|
4499
4513
|
}
|
|
4500
4514
|
|
|
4515
|
+
// ../server/src/internal/workspace/workbench-store.ts
|
|
4516
|
+
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
4517
|
+
import { join as join8 } from "node:path";
|
|
4518
|
+
var LAYOUT_FILE = "workbench.json";
|
|
4519
|
+
var DRAFTS_FILE = "drafts.json";
|
|
4520
|
+
var LAYOUT_MAX_BYTES = 256 * 1024;
|
|
4521
|
+
var DRAFTS_MAX_BYTES = 32 * 1024 * 1024;
|
|
4522
|
+
function readWorkbench(dataDir) {
|
|
4523
|
+
return readSlot(join8(dataDir, LAYOUT_FILE), LAYOUT_MAX_BYTES);
|
|
4524
|
+
}
|
|
4525
|
+
function saveWorkbench(dataDir, snapshot) {
|
|
4526
|
+
return saveSlot(dataDir, LAYOUT_FILE, snapshot, LAYOUT_MAX_BYTES);
|
|
4527
|
+
}
|
|
4528
|
+
function readDrafts(dataDir) {
|
|
4529
|
+
return readSlot(join8(dataDir, DRAFTS_FILE), DRAFTS_MAX_BYTES);
|
|
4530
|
+
}
|
|
4531
|
+
function saveDrafts(dataDir, snapshot) {
|
|
4532
|
+
return saveSlot(dataDir, DRAFTS_FILE, snapshot, DRAFTS_MAX_BYTES);
|
|
4533
|
+
}
|
|
4534
|
+
function readSlot(path, maxBytes) {
|
|
4535
|
+
let raw;
|
|
4536
|
+
try {
|
|
4537
|
+
raw = readFileSync(path, "utf8");
|
|
4538
|
+
} catch {
|
|
4539
|
+
return void 0;
|
|
4540
|
+
}
|
|
4541
|
+
if (raw.length > maxBytes) {
|
|
4542
|
+
return void 0;
|
|
4543
|
+
}
|
|
4544
|
+
let parsed;
|
|
4545
|
+
try {
|
|
4546
|
+
parsed = JSON.parse(raw);
|
|
4547
|
+
} catch {
|
|
4548
|
+
return void 0;
|
|
4549
|
+
}
|
|
4550
|
+
return asSnapshot(parsed);
|
|
4551
|
+
}
|
|
4552
|
+
function saveSlot(dataDir, file, snapshot, maxBytes) {
|
|
4553
|
+
const valid = asSnapshot(snapshot);
|
|
4554
|
+
if (valid === void 0) {
|
|
4555
|
+
throw new UnsupportedByHostError(`Saving ${file} needs a { version, data } snapshot.`);
|
|
4556
|
+
}
|
|
4557
|
+
const serialized = JSON.stringify(valid);
|
|
4558
|
+
if (Buffer.byteLength(serialized, "utf8") > maxBytes) {
|
|
4559
|
+
throw new UnsupportedByHostError(`That ${file} snapshot is too large to save.`);
|
|
4560
|
+
}
|
|
4561
|
+
const target = join8(dataDir, file);
|
|
4562
|
+
const temp = `${target}.${process.pid}.tmp`;
|
|
4563
|
+
try {
|
|
4564
|
+
mkdirSync(dataDir, { recursive: true });
|
|
4565
|
+
writeFileSync(temp, serialized);
|
|
4566
|
+
renameSync(temp, target);
|
|
4567
|
+
return true;
|
|
4568
|
+
} catch {
|
|
4569
|
+
try {
|
|
4570
|
+
writeFileSync(target, serialized);
|
|
4571
|
+
return true;
|
|
4572
|
+
} catch {
|
|
4573
|
+
rmSync(temp, { force: true });
|
|
4574
|
+
return false;
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
}
|
|
4578
|
+
function asSnapshot(value) {
|
|
4579
|
+
if (typeof value !== "object" || value === null) {
|
|
4580
|
+
return void 0;
|
|
4581
|
+
}
|
|
4582
|
+
const candidate = value;
|
|
4583
|
+
const version = candidate["version"];
|
|
4584
|
+
if (typeof version !== "number" || !Number.isInteger(version) || version < 1) {
|
|
4585
|
+
return void 0;
|
|
4586
|
+
}
|
|
4587
|
+
return { version, data: candidate["data"] };
|
|
4588
|
+
}
|
|
4589
|
+
|
|
4501
4590
|
// ../server/src/internal/ws/session-factory.service.ts
|
|
4502
4591
|
var MorseSessionFactory = class {
|
|
4503
4592
|
constructor(registry, transcripts, policy, logger, config, terminal) {
|
|
@@ -4532,6 +4621,10 @@ var MorseSessionFactory = class {
|
|
|
4532
4621
|
// the bottom panel's terminal is this host's. It runs in the viewing
|
|
4533
4622
|
// session's directory and is gated by `ProjectPolicy`, like a session.
|
|
4534
4623
|
terminal: true,
|
|
4624
|
+
// The browser host restores the tabs, panel, terminals and half-written
|
|
4625
|
+
// prompts the reader left open, kept under `<MORSE_HOME>`. VS Code has its
|
|
4626
|
+
// own tab restoration and leaves this off.
|
|
4627
|
+
workbench: true,
|
|
4535
4628
|
// A browser cannot hand a dragged file's path to pi, so the host takes the
|
|
4536
4629
|
// bytes and writes them next to the session; the frontend then `@mentions`
|
|
4537
4630
|
// the path it gets back.
|
|
@@ -4595,13 +4688,25 @@ var MorseSessionFactory = class {
|
|
|
4595
4688
|
});
|
|
4596
4689
|
return { ...listing, canOpen: this.policy.canOpen(listing.path) };
|
|
4597
4690
|
}
|
|
4691
|
+
case "readWorkbench": {
|
|
4692
|
+
return readWorkbench(this.config.dataDir) ?? null;
|
|
4693
|
+
}
|
|
4694
|
+
case "saveWorkbench": {
|
|
4695
|
+
return { ok: saveWorkbench(this.config.dataDir, args) };
|
|
4696
|
+
}
|
|
4697
|
+
case "readDrafts": {
|
|
4698
|
+
return readDrafts(this.config.dataDir) ?? null;
|
|
4699
|
+
}
|
|
4700
|
+
case "saveDrafts": {
|
|
4701
|
+
return { ok: saveDrafts(this.config.dataDir, args) };
|
|
4702
|
+
}
|
|
4598
4703
|
case "listFiles": {
|
|
4599
4704
|
const cwd = this.requireWritableCwd(context);
|
|
4600
4705
|
const files = await workspaceFiles(cwd, this.logger, { fresh: args?.fresh === true });
|
|
4601
4706
|
return { files };
|
|
4602
4707
|
}
|
|
4603
4708
|
case "readFile": {
|
|
4604
|
-
const cwd = this.
|
|
4709
|
+
const cwd = this.commandCwd(context, args);
|
|
4605
4710
|
const path = typeof args?.path === "string" ? args.path : "";
|
|
4606
4711
|
if (path.length === 0) {
|
|
4607
4712
|
throw new UnsupportedByHostError('readFile needs a "path" argument.');
|
|
@@ -4625,7 +4730,7 @@ var MorseSessionFactory = class {
|
|
|
4625
4730
|
return readGitStatus(cwd);
|
|
4626
4731
|
}
|
|
4627
4732
|
case "gitDiff": {
|
|
4628
|
-
const cwd = this.
|
|
4733
|
+
const cwd = this.commandCwd(context, args);
|
|
4629
4734
|
const path = typeof args?.path === "string" ? args.path : "";
|
|
4630
4735
|
if (path.length === 0) {
|
|
4631
4736
|
throw new UnsupportedByHostError('gitDiff needs a "path" argument.');
|
|
@@ -4646,7 +4751,7 @@ var MorseSessionFactory = class {
|
|
|
4646
4751
|
return readCommitFiles(cwd, hash);
|
|
4647
4752
|
}
|
|
4648
4753
|
case "gitCommitDiff": {
|
|
4649
|
-
const cwd = this.
|
|
4754
|
+
const cwd = this.commandCwd(context, args);
|
|
4650
4755
|
const hash = typeof args?.hash === "string" ? args.hash : "";
|
|
4651
4756
|
const path = typeof args?.path === "string" ? args.path : "";
|
|
4652
4757
|
if (path.length === 0) {
|
|
@@ -4699,6 +4804,22 @@ var MorseSessionFactory = class {
|
|
|
4699
4804
|
}
|
|
4700
4805
|
return cwd;
|
|
4701
4806
|
}
|
|
4807
|
+
/**
|
|
4808
|
+
* The directory a file command works in. A restored preview tab carries the
|
|
4809
|
+
* project it was read from (`args.cwd`), because the host may still be on
|
|
4810
|
+
* another session when that tab is loaded; the policy checks it exactly like a
|
|
4811
|
+
* terminal's directory. Without one, the viewing session's directory is used.
|
|
4812
|
+
*/
|
|
4813
|
+
commandCwd(context, args) {
|
|
4814
|
+
const requested = args?.cwd;
|
|
4815
|
+
if (typeof requested === "string" && requested.length > 0) {
|
|
4816
|
+
if (!this.policy.canOpen(requested)) {
|
|
4817
|
+
throw new UnsupportedByHostError(`Morse is not allowed to work in ${requested}.`);
|
|
4818
|
+
}
|
|
4819
|
+
return requested;
|
|
4820
|
+
}
|
|
4821
|
+
return this.requireWritableCwd(context);
|
|
4822
|
+
}
|
|
4702
4823
|
/** The cwd of the session this connection is showing. */
|
|
4703
4824
|
activeCwd() {
|
|
4704
4825
|
const key = this.registry.activeKeyOf();
|
|
@@ -4771,18 +4892,19 @@ MorseGateway = __decorateClass([
|
|
|
4771
4892
|
], MorseGateway);
|
|
4772
4893
|
|
|
4773
4894
|
// ../server/src/app/config.ts
|
|
4774
|
-
import { basename as basename4, dirname as dirname2, isAbsolute as isAbsolute6, join as
|
|
4775
|
-
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
4895
|
+
import { basename as basename4, dirname as dirname2, isAbsolute as isAbsolute6, join as join9 } from "node:path";
|
|
4896
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
4897
|
+
import { homedir as homedir4 } from "node:os";
|
|
4776
4898
|
import { fileURLToPath } from "node:url";
|
|
4777
4899
|
function loadConfig(env = process.env) {
|
|
4778
4900
|
const workspacePath = resolveWorkspacePath(env);
|
|
4779
4901
|
const configuredUiDir = env.MORSE_UI_DIR;
|
|
4780
4902
|
const moduleDir = dirname2(fileURLToPath(import.meta.url));
|
|
4781
|
-
const bundledUiDir =
|
|
4782
|
-
const monorepoUiDir =
|
|
4783
|
-
const defaultUiDir = existsSync2(
|
|
4903
|
+
const bundledUiDir = join9(moduleDir, "ui");
|
|
4904
|
+
const monorepoUiDir = join9(moduleDir, "..", "..", "..", "ui-angular", "dist");
|
|
4905
|
+
const defaultUiDir = existsSync2(join9(bundledUiDir, "index.html")) ? bundledUiDir : monorepoUiDir;
|
|
4784
4906
|
const defaultHost = "127.0.0.1";
|
|
4785
|
-
const uiDir = configuredUiDir ? isAbsolute6(configuredUiDir) ? configuredUiDir :
|
|
4907
|
+
const uiDir = configuredUiDir ? isAbsolute6(configuredUiDir) ? configuredUiDir : join9(process.cwd(), configuredUiDir) : defaultUiDir;
|
|
4786
4908
|
return {
|
|
4787
4909
|
host: env.MORSE_HOST ?? defaultHost,
|
|
4788
4910
|
port: parsePositiveInt(env.MORSE_PORT, 4399),
|
|
@@ -4797,6 +4919,7 @@ function loadConfig(env = process.env) {
|
|
|
4797
4919
|
hotSessions: parsePositiveInt(env.MORSE_HOT_SESSIONS, 4),
|
|
4798
4920
|
projects: parseList(env.MORSE_PROJECTS),
|
|
4799
4921
|
uploadDir: env.MORSE_UPLOAD_DIR?.trim() || DEFAULT_UPLOAD_DIR,
|
|
4922
|
+
dataDir: resolveDataDir(env),
|
|
4800
4923
|
updateCheck: !isOff(env.MORSE_UPDATE_CHECK),
|
|
4801
4924
|
instance: env.MORSE_INSTANCE?.trim() || void 0
|
|
4802
4925
|
};
|
|
@@ -4804,12 +4927,16 @@ function loadConfig(env = process.env) {
|
|
|
4804
4927
|
function readFrontendIdentity(uiDir) {
|
|
4805
4928
|
try {
|
|
4806
4929
|
return frontendIdentity(
|
|
4807
|
-
parseFrontendManifest(
|
|
4930
|
+
parseFrontendManifest(readFileSync2(join9(uiDir, FRONTEND_MANIFEST_FILE), "utf8"))
|
|
4808
4931
|
);
|
|
4809
4932
|
} catch {
|
|
4810
4933
|
return void 0;
|
|
4811
4934
|
}
|
|
4812
4935
|
}
|
|
4936
|
+
function resolveDataDir(env) {
|
|
4937
|
+
const explicit = env.MORSE_HOME?.trim();
|
|
4938
|
+
return explicit && explicit.length > 0 ? explicit : join9(homedir4(), ".morse");
|
|
4939
|
+
}
|
|
4813
4940
|
function parsePositiveInt(value, fallback) {
|
|
4814
4941
|
if (!value) {
|
|
4815
4942
|
return fallback;
|
|
@@ -4835,7 +4962,7 @@ function resolveWorkspacePath(env) {
|
|
|
4835
4962
|
const start = process.cwd();
|
|
4836
4963
|
let directory = start;
|
|
4837
4964
|
for (; ; ) {
|
|
4838
|
-
const manifest =
|
|
4965
|
+
const manifest = join9(directory, "package.json");
|
|
4839
4966
|
if (existsSync2(manifest) && declaresWorkspaces(manifest)) {
|
|
4840
4967
|
return directory;
|
|
4841
4968
|
}
|
|
@@ -4848,7 +4975,7 @@ function resolveWorkspacePath(env) {
|
|
|
4848
4975
|
}
|
|
4849
4976
|
function declaresWorkspaces(manifestPath) {
|
|
4850
4977
|
try {
|
|
4851
|
-
const manifest = JSON.parse(
|
|
4978
|
+
const manifest = JSON.parse(readFileSync2(manifestPath, "utf8"));
|
|
4852
4979
|
return manifest.workspaces !== void 0;
|
|
4853
4980
|
} catch {
|
|
4854
4981
|
return false;
|